@sjtdev/koishi-plugin-dota2tracker 2.2.3 → 2.3.1

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.
Files changed (105) hide show
  1. package/changelog.md +28 -0
  2. package/lib/index.js +200 -162
  3. package/{queries → lib/queries}/MatchInfo.graphql +13 -0
  4. package/lib/templates/common/components/building_icons.ejs +20 -0
  5. package/lib/templates/common/styles/normalize.min.css +1 -0
  6. package/lib/templates/hero/hero_1.ejs +69 -0
  7. package/lib/templates/images/7.38_simple_minimap.png +0 -0
  8. package/lib/templates/item/item/recipe.ejs +9 -0
  9. package/lib/templates/item/item/style.css +1 -0
  10. package/lib/templates/item/item.ejs +52 -0
  11. package/lib/templates/item/itemlist.ejs +11 -0
  12. package/lib/templates/match/match_1/base.css +1 -0
  13. package/lib/templates/match/match_1/item.ejs +1 -0
  14. package/lib/templates/match/match_1/main.ejs +8 -0
  15. package/lib/templates/match/match_1/player.ejs +1 -0
  16. package/lib/templates/match/match_1/style.css +1 -0
  17. package/lib/templates/match/match_1.ejs +18 -0
  18. package/lib/templates/match/match_2/original.css +1 -0
  19. package/lib/templates/match/match_2/original.ejs +10 -0
  20. package/lib/templates/match/match_2+/charts.ejs +1 -0
  21. package/lib/templates/match/match_2+/extra.css +1 -0
  22. package/lib/templates/match/match_2+/lane_outcome.ejs +56 -0
  23. package/lib/templates/match/match_2+/map.ejs +160 -0
  24. package/lib/templates/match/match_2+.ejs +1 -0
  25. package/lib/templates/match/match_2.ejs +1 -0
  26. package/lib/templates/player/player_1/base.css +1 -0
  27. package/lib/templates/player/player_1/private.ejs +1 -0
  28. package/lib/templates/player/player_1.ejs +78 -0
  29. package/lib/templates/rank/rank_fun.ejs +1 -0
  30. package/lib/templates/report/daily/base.css +1 -0
  31. package/lib/templates/report/daily.ejs +29 -0
  32. package/package.json +2 -2
  33. package/template/hero/hero_1.ejs +0 -900
  34. package/template/item/item/recipe.ejs +0 -51
  35. package/template/item/item/style.css +0 -244
  36. package/template/item/item.ejs +0 -140
  37. package/template/item/itemlist.ejs +0 -99
  38. package/template/match/match_1/item.ejs +0 -11
  39. package/template/match/match_1/main.ejs +0 -37
  40. package/template/match/match_1/player.ejs +0 -154
  41. package/template/match/match_1/style.css +0 -764
  42. package/template/match/match_1.ejs +0 -56
  43. package/template/match/match_2/original.css +0 -463
  44. package/template/match/match_2/original.ejs +0 -192
  45. package/template/match/match_2+/charts.ejs +0 -261
  46. package/template/match/match_2+/extra.css +0 -143
  47. package/template/match/match_2+/lane_outcome.ejs +0 -157
  48. package/template/match/match_2+.ejs +0 -27
  49. package/template/match/match_2.ejs +0 -18
  50. package/template/player/player_1/private.ejs +0 -5
  51. package/template/player/player_1.ejs +0 -654
  52. package/template/rank/rank_fun.ejs +0 -131
  53. package/template/report/daily.ejs +0 -191
  54. /package/{queries → lib/queries}/Constants.graphql +0 -0
  55. /package/{queries → lib/queries}/GetWeeklyMetaByPosition.graphql +0 -0
  56. /package/{queries → lib/queries}/PlayerExtraInfo.graphql +0 -0
  57. /package/{queries → lib/queries}/PlayerInfoWith25Matches.graphql +0 -0
  58. /package/{queries → lib/queries}/PlayerPerformanceForHeroRecommendation.graphql +0 -0
  59. /package/{queries → lib/queries}/PlayersInfoWith10MatchesForGuild.graphql +0 -0
  60. /package/{queries → lib/queries}/PlayersLastmatchRankinfo.graphql +0 -0
  61. /package/{queries → lib/queries}/PlayersMatchesForDaily.graphql +0 -0
  62. /package/{queries → lib/queries}/RequestMatchDataAnalysis.graphql +0 -0
  63. /package/{queries → lib/queries}/VerifyingPlayer.graphql +0 -0
  64. /package/{template → lib/templates}/images/bei.jpg +0 -0
  65. /package/{template → lib/templates}/images/disconnected.png +0 -0
  66. /package/{template → lib/templates}/images/flag_dire.png +0 -0
  67. /package/{template → lib/templates}/images/flag_radiant.png +0 -0
  68. /package/{template → lib/templates}/images/hero_badge_1.png +0 -0
  69. /package/{template → lib/templates}/images/hero_badge_2.png +0 -0
  70. /package/{template → lib/templates}/images/hero_badge_3.png +0 -0
  71. /package/{template → lib/templates}/images/hero_badge_4.png +0 -0
  72. /package/{template → lib/templates}/images/hero_badge_5.png +0 -0
  73. /package/{template → lib/templates}/images/hero_badge_6.png +0 -0
  74. /package/{template → lib/templates}/images/lane_fail.svg +0 -0
  75. /package/{template → lib/templates}/images/lane_jungle.svg +0 -0
  76. /package/{template → lib/templates}/images/lane_stomp.svg +0 -0
  77. /package/{template → lib/templates}/images/lane_stomped.svg +0 -0
  78. /package/{template → lib/templates}/images/lane_tie.svg +0 -0
  79. /package/{template → lib/templates}/images/lane_victory.svg +0 -0
  80. /package/{template → lib/templates}/images/logo_dire.png +0 -0
  81. /package/{template → lib/templates}/images/logo_radiant.png +0 -0
  82. /package/{template → lib/templates}/images/medal_0.png +0 -0
  83. /package/{template → lib/templates}/images/medal_1.png +0 -0
  84. /package/{template → lib/templates}/images/medal_2.png +0 -0
  85. /package/{template → lib/templates}/images/medal_3.png +0 -0
  86. /package/{template → lib/templates}/images/medal_4.png +0 -0
  87. /package/{template → lib/templates}/images/medal_5.png +0 -0
  88. /package/{template → lib/templates}/images/medal_6.png +0 -0
  89. /package/{template → lib/templates}/images/medal_7.png +0 -0
  90. /package/{template → lib/templates}/images/medal_8.png +0 -0
  91. /package/{template → lib/templates}/images/medal_8b.png +0 -0
  92. /package/{template → lib/templates}/images/medal_8c.png +0 -0
  93. /package/{template → lib/templates}/images/scepter.png +0 -0
  94. /package/{template → lib/templates}/images/scepter_0.png +0 -0
  95. /package/{template → lib/templates}/images/scepter_1.png +0 -0
  96. /package/{template → lib/templates}/images/shard.png +0 -0
  97. /package/{template → lib/templates}/images/shard_0.png +0 -0
  98. /package/{template → lib/templates}/images/shard_1.png +0 -0
  99. /package/{template → lib/templates}/images/star_0.png +0 -0
  100. /package/{template → lib/templates}/images/star_1.png +0 -0
  101. /package/{template → lib/templates}/images/star_2.png +0 -0
  102. /package/{template → lib/templates}/images/star_3.png +0 -0
  103. /package/{template → lib/templates}/images/star_4.png +0 -0
  104. /package/{template → lib/templates}/images/star_5.png +0 -0
  105. /package/{template → lib/templates}/images/xi.jpg +0 -0
package/lib/index.js CHANGED
@@ -259,7 +259,8 @@ var require_en_US_constants = __commonJS({
259
259
  "136": "Marci",
260
260
  "137": "Primal Beast",
261
261
  "138": "Muerta",
262
- "145": "Kez"
262
+ "145": "Kez",
263
+ "155": "Largo"
263
264
  },
264
265
  behavior: {
265
266
  "Unit Target": "Unit Target",
@@ -571,7 +572,8 @@ var require_zh_CN_constants = __commonJS({
571
572
  "136": "玛西",
572
573
  "137": "獸",
573
574
  "138": "琼英碧灵",
574
- "145": "凯"
575
+ "145": "凯",
576
+ "155": "朗戈"
575
577
  },
576
578
  behavior: {
577
579
  "Unit Target": "单位目标",
@@ -833,7 +835,6 @@ var import_path5 = __toESM(require("path"));
833
835
 
834
836
  // src/app/common/i18n.ts
835
837
  var import_koishi = require("koishi");
836
- var dotaconstants = __toESM(require("dotaconstants"));
837
838
 
838
839
  // src/app/common/utils.ts
839
840
  var import_luxon = require("luxon");
@@ -925,14 +926,9 @@ var LanguageTags = {
925
926
  "zh-CN": { graphqlTag: "S_CHINESE", valveTag: "schinese" }
926
927
  };
927
928
  var I18NService = class extends import_koishi.Service {
928
- static {
929
- __name(this, "I18NService");
930
- }
931
- constantLocales = {};
932
- i18n;
933
- globalLanguageTag;
934
- constructor(ctx) {
929
+ constructor(ctx, dotaconstants) {
935
930
  super(ctx, "dota2tracker.i18n", true);
931
+ this.dotaconstants = dotaconstants;
936
932
  this.config = ctx.config;
937
933
  this.i18n = this.ctx.i18n;
938
934
  for (const supportLanguageTag of Object.keys(LanguageTags)) {
@@ -943,6 +939,12 @@ var I18NService = class extends import_koishi.Service {
943
939
  }
944
940
  this.globalLanguageTag = this.i18n.fallback(Object.values(this.i18n.locales).map((locale) => Object.keys(locale).at(0))).find((locale) => Object.keys(LanguageTags).includes(locale));
945
941
  }
942
+ static {
943
+ __name(this, "I18NService");
944
+ }
945
+ constantLocales = {};
946
+ i18n;
947
+ globalLanguageTag;
946
948
  getGraphqlLanguageTag(languageTag) {
947
949
  return LanguageTags[languageTag].graphqlTag;
948
950
  }
@@ -1048,7 +1050,7 @@ var I18NService = class extends import_koishi.Service {
1048
1050
  */
1049
1051
  _buildNicknameMap(languageTag) {
1050
1052
  this.logger.debug(`Building nickname map for ${languageTag}...`);
1051
- const heroIds = Object.keys(dotaconstants.heroes).map(Number);
1053
+ const heroIds = Object.keys(this.dotaconstants.heroes).map(Number);
1052
1054
  const nicknameMap = /* @__PURE__ */ new Map();
1053
1055
  for (const heroId of heroIds) {
1054
1056
  const allNames = this._getAllHeroNames(heroId, languageTag);
@@ -1063,7 +1065,7 @@ var I18NService = class extends import_koishi.Service {
1063
1065
  const inputStr = String(input).toLowerCase();
1064
1066
  if (/^\d+$/.test(inputStr)) {
1065
1067
  const heroId = Number(inputStr);
1066
- if (dotaconstants.heroes[heroId]) {
1068
+ if (this.dotaconstants.heroes[heroId]) {
1067
1069
  return heroId;
1068
1070
  }
1069
1071
  }
@@ -1089,7 +1091,6 @@ var I18NService = class extends import_koishi.Service {
1089
1091
 
1090
1092
  // src/app/core/hero.service.ts
1091
1093
  var import_koishi2 = require("koishi");
1092
- var dotaconstants2 = __toESM(require("dotaconstants"));
1093
1094
  var import_luxon2 = require("luxon");
1094
1095
 
1095
1096
  // src/app/common/constants.ts
@@ -1098,12 +1099,13 @@ var RANK_BRACKETS = ["UNCALIBRATED", "HERALD", "GUARDIAN", "CRUSADER", "ARCHON",
1098
1099
 
1099
1100
  // src/app/core/hero.service.ts
1100
1101
  var HeroService = class _HeroService extends import_koishi2.Service {
1102
+ constructor(ctx, dotaconstants) {
1103
+ super(ctx, "dota2tracker.hero", true);
1104
+ this.dotaconstants = dotaconstants;
1105
+ }
1101
1106
  static {
1102
1107
  __name(this, "HeroService");
1103
1108
  }
1104
- constructor(ctx) {
1105
- super(ctx, "dota2tracker.hero", true);
1106
- }
1107
1109
  async getWeeklyHeroMeta(rank) {
1108
1110
  const MINIMUM_PICK_RATE = 0.02;
1109
1111
  const RECOMMENDATION_COUNT = 3;
@@ -1138,7 +1140,7 @@ var HeroService = class _HeroService extends import_koishi2.Service {
1138
1140
  return weeklyHeroMeta;
1139
1141
  }
1140
1142
  async getHeroDetails(input, languageTag, isRandom = false) {
1141
- const heroId = this.ctx.dota2tracker.i18n.findHeroIdInLocale(isRandom ? import_koishi2.Random.pick(Object.keys(dotaconstants2.heroes)) : input);
1143
+ const heroId = this.ctx.dota2tracker.i18n.findHeroIdInLocale(isRandom ? import_koishi2.Random.pick(Object.keys(this.dotaconstants.heroes)) : input);
1142
1144
  if (!heroId) return;
1143
1145
  return _HeroService.formatHeroDetails(await this.ctx.dota2tracker.valveAPI.queryHeroDetailsFromValve(heroId, languageTag));
1144
1146
  }
@@ -1298,7 +1300,7 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1298
1300
  }
1299
1301
  static getFormattedItemListData(rawItems) {
1300
1302
  const processItemName = /* @__PURE__ */ __name((name2) => name2.replace(/^item_/i, "").replace(/^recipe_/i, "recipe_"), "processItemName");
1301
- const [recipes, items3] = rawItems.reduce(
1303
+ const [recipes, items] = rawItems.reduce(
1302
1304
  (acc, item) => {
1303
1305
  const processed = {
1304
1306
  ...item,
@@ -1312,14 +1314,14 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1312
1314
  [[], []]
1313
1315
  );
1314
1316
  const itemMap = /* @__PURE__ */ new Map();
1315
- items3.concat(recipes).forEach(
1317
+ items.concat(recipes).forEach(
1316
1318
  (item) => itemMap.set(item.id, {
1317
1319
  id: item.id,
1318
1320
  name: item.name,
1319
1321
  name_loc: item.name_loc
1320
1322
  })
1321
1323
  );
1322
- const processedItems = items3.map((baseItem) => {
1324
+ const processedItems = items.map((baseItem) => {
1323
1325
  const recipe = recipes.find((r) => r.name === `recipe_${baseItem.name.replace("item_", "")}`);
1324
1326
  return {
1325
1327
  ...baseItem,
@@ -1352,19 +1354,19 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1352
1354
  }))
1353
1355
  }));
1354
1356
  }
1355
- searchItems(items3, keyword, languageTag, config) {
1357
+ searchItems(items, keyword, languageTag, config) {
1356
1358
  if (!keyword) return [];
1357
1359
  const alias = this.ctx.dota2tracker.i18n.getConstantLocale(languageTag).dota2tracker.items_alias?.[keyword] ?? config.customItemAlias.filter((cia) => cia.alias == keyword).map((cia) => cia.keyword);
1358
- const exactMatch = items3.filter(
1360
+ const exactMatch = items.filter(
1359
1361
  (item) => alias?.some((a) => item.name_loc.trim().toLowerCase() == a.toLowerCase()) || item.name_loc.trim().toLowerCase() === keyword.trim().toLowerCase() || Number.isInteger(Number(keyword)) && item.id === Number(keyword)
1360
1362
  );
1361
1363
  if (exactMatch.length) return exactMatch;
1362
- return this.fuzzySearchItems(alias.length ? alias : [keyword], items3);
1364
+ return this.fuzzySearchItems(alias.length ? alias : [keyword], items);
1363
1365
  }
1364
- fuzzySearchItems(keywords, items3) {
1366
+ fuzzySearchItems(keywords, items) {
1365
1367
  const resultMap = /* @__PURE__ */ new Map();
1366
1368
  if (!keywords.length) return [];
1367
- for (const item of items3) {
1369
+ for (const item of items) {
1368
1370
  const cleanName = item.name_loc.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").trim();
1369
1371
  let matchAllKeywords = true;
1370
1372
  for (const keyword of keywords) {
@@ -1391,7 +1393,6 @@ var ItemService = class _ItemService extends import_koishi3.Service {
1391
1393
 
1392
1394
  // src/app/core/match.service.ts
1393
1395
  var import_koishi4 = require("koishi");
1394
- var dotaconstants3 = __toESM(require("dotaconstants"));
1395
1396
 
1396
1397
  // src/app/common/error.ts
1397
1398
  var import_util = require("util");
@@ -1520,9 +1521,10 @@ __name(handleError, "handleError");
1520
1521
 
1521
1522
  // src/app/core/match.service.ts
1522
1523
  var MatchService = class _MatchService extends import_koishi4.Service {
1523
- constructor(ctx, pluginVersion2) {
1524
+ constructor(ctx, pluginVersion, dotaconstants) {
1524
1525
  super(ctx, "dota2tracker.match", true);
1525
- this.pluginVersion = pluginVersion2;
1526
+ this.pluginVersion = pluginVersion;
1527
+ this.dotaconstants = dotaconstants;
1526
1528
  }
1527
1529
  static {
1528
1530
  __name(this, "MatchService");
@@ -1627,7 +1629,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1627
1629
  }
1628
1630
  const facetData = await _MatchService.constantsInjectFacetData(constantsQuery, matchQuery, languageTag, this.ctx.dota2tracker.hero);
1629
1631
  this.ctx.dota2tracker.cache.setFacetConstantsCache(languageTag, constantsQuery);
1630
- const match = _MatchService.extendMatchData(matchQuery, facetData);
1632
+ const match = _MatchService.extendMatchData(matchQuery, facetData, this.dotaconstants);
1631
1633
  return match;
1632
1634
  } catch (error) {
1633
1635
  this.ctx.dota2tracker.cache.deleteFacetConstantsCache(languageTag);
@@ -1652,7 +1654,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1652
1654
  return facetData;
1653
1655
  }
1654
1656
  // 对比赛数据进行补充以供生成模板函数使用
1655
- static extendMatchData(matchQuery, facetData) {
1657
+ static extendMatchData(matchQuery, facetData, dotaconstants) {
1656
1658
  const match = matchQuery.match;
1657
1659
  const matchParsed = _MatchService.isMatchParsed(matchQuery);
1658
1660
  ["radiant", "dire"].forEach((team) => {
@@ -1772,9 +1774,9 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1772
1774
  }
1773
1775
  purchaseTimesMap[item.itemId].push(item.time);
1774
1776
  } else {
1775
- const itemName = dotaconstants3.item_ids[item.itemId];
1777
+ const itemName = dotaconstants.item_ids[item.itemId];
1776
1778
  if (itemName) {
1777
- const itemDetails = dotaconstants3.items[itemName];
1779
+ const itemDetails = dotaconstants.items[itemName];
1778
1780
  if (itemDetails && itemDetails.cost) {
1779
1781
  player.utilityScore += itemDetails.cost;
1780
1782
  }
@@ -1787,7 +1789,7 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1787
1789
  for (let itemId in supportItemsCount) {
1788
1790
  if (supportItemsCount[itemId] === 0) continue;
1789
1791
  player.supportItemsCount.push({
1790
- name: dotaconstants3.item_ids[itemId],
1792
+ name: dotaconstants.item_ids[itemId],
1791
1793
  count: supportItemsCount[itemId]
1792
1794
  });
1793
1795
  }
@@ -1795,13 +1797,13 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1795
1797
  player.items = [];
1796
1798
  for (let i = 0; i <= 5; i++) {
1797
1799
  const itemId = player[`item${i}Id`];
1798
- const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices);
1800
+ const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices, dotaconstants);
1799
1801
  player.items.push(itemObject);
1800
1802
  }
1801
1803
  player.backpacks = [];
1802
1804
  for (let i = 0; i <= 2; i++) {
1803
1805
  const itemId = player[`backpack${i}Id`];
1804
- const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices);
1806
+ const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices, dotaconstants);
1805
1807
  player.backpacks.push(itemObject);
1806
1808
  }
1807
1809
  if (player.additionalUnit) {
@@ -1809,12 +1811,12 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1809
1811
  player.unitBackpacks = [];
1810
1812
  for (let i = 0; i <= 5; i++) {
1811
1813
  const itemId = player.additionalUnit[`item${i}Id`];
1812
- const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices);
1814
+ const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices, dotaconstants);
1813
1815
  player.unitItems.push(itemObject);
1814
1816
  }
1815
1817
  for (let i = 0; i <= 2; i++) {
1816
1818
  const itemId = player.additionalUnit[`backpack${i}Id`];
1817
- const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices);
1819
+ const itemObject = createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices, dotaconstants);
1818
1820
  player.unitBackpacks.push(itemObject);
1819
1821
  }
1820
1822
  }
@@ -1893,15 +1895,15 @@ var MatchService = class _MatchService extends import_koishi4.Service {
1893
1895
  return matchQuery?.match?.parsedDateTime && matchQuery?.match?.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0;
1894
1896
  }
1895
1897
  };
1896
- function createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices) {
1898
+ function createItemObject(itemId, purchaseTimesMap, purchaseTimeIndices, dotaconstants) {
1897
1899
  if (itemId === void 0 || itemId === null) {
1898
1900
  return null;
1899
1901
  }
1900
- if (dotaconstants3.item_ids[itemId]) {
1902
+ if (dotaconstants.item_ids[itemId]) {
1901
1903
  const currentIndex = purchaseTimeIndices.get(itemId) || 0;
1902
1904
  const seconds = purchaseTimesMap[itemId]?.[currentIndex];
1903
1905
  purchaseTimeIndices.set(itemId, currentIndex + 1);
1904
- const name2 = dotaconstants3.item_ids[itemId];
1906
+ const name2 = dotaconstants.item_ids[itemId];
1905
1907
  const prefix = "recipe_";
1906
1908
  const isRecipe = name2.startsWith(prefix);
1907
1909
  const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
@@ -1919,16 +1921,16 @@ __name(createItemObject, "createItemObject");
1919
1921
 
1920
1922
  // src/app/core/player.service.ts
1921
1923
  var import_koishi5 = require("koishi");
1922
- var dotaconstants4 = __toESM(require("dotaconstants"));
1923
1924
  var import_luxon3 = require("luxon");
1924
1925
  var PlayerService = class _PlayerService extends import_koishi5.Service {
1925
- static {
1926
- __name(this, "PlayerService");
1927
- }
1928
- constructor(ctx) {
1926
+ constructor(ctx, dotaconstants) {
1929
1927
  super(ctx, "dota2tracker.player", true);
1928
+ this.dotaconstants = dotaconstants;
1930
1929
  this.config = ctx.config;
1931
1930
  }
1931
+ static {
1932
+ __name(this, "PlayerService");
1933
+ }
1932
1934
  async getHeroRecommendation(steamId, player) {
1933
1935
  const RECENT_IMP_WEIGHT = 0.1;
1934
1936
  const LIFETIME_WIN_LOG_WEIGHT = 5;
@@ -2027,12 +2029,12 @@ var PlayerService = class _PlayerService extends import_koishi5.Service {
2027
2029
  const lastMatchQuery = await this.ctx.dota2tracker.stratzAPI.queryPlayersLastMatchRankInfo({
2028
2030
  steamAccountIds: [steamId]
2029
2031
  });
2030
- if (lastMatchQuery.players[0].steamAccount.isAnonymous) return { matchId: 0, isAnonymous: true };
2032
+ if (lastMatchQuery.players[0].steamAccount.isAnonymous) return { id: 0, isAnonymous: true };
2031
2033
  lastMatchId = lastMatchQuery.players[0].matches[0]?.id;
2032
2034
  } catch (error) {
2033
2035
  this.logger.error(error);
2034
2036
  }
2035
- return { matchId: lastMatchId };
2037
+ return { id: lastMatchId };
2036
2038
  }
2037
2039
  async getFormattedPlayerData(steamId, heroId, languageTag) {
2038
2040
  const playerQuery = await this.ctx.dota2tracker.stratzAPI.queryPlayerInfoWith25Matches({
@@ -2049,12 +2051,15 @@ var PlayerService = class _PlayerService extends import_koishi5.Service {
2049
2051
  dotaPlus: null
2050
2052
  }
2051
2053
  };
2052
- const player = _PlayerService.extendPlayerData({
2053
- playerQuery,
2054
- playerExtraQuery,
2055
- genHero: heroId ? { heroId, name: this.ctx.dota2tracker.i18n.getConstantLocale(languageTag).dota2tracker.template.hero_names[heroId] } : null,
2056
- estimateRank: this.config.playerRankEstimate
2057
- });
2054
+ const player = _PlayerService.extendPlayerData(
2055
+ {
2056
+ playerQuery,
2057
+ playerExtraQuery,
2058
+ genHero: heroId ? { heroId, name: this.ctx.dota2tracker.i18n.getConstantLocale(languageTag).dota2tracker.template.hero_names[heroId] } : null,
2059
+ estimateRank: this.config.playerRankEstimate
2060
+ },
2061
+ this.dotaconstants
2062
+ );
2058
2063
  return player;
2059
2064
  }
2060
2065
  async validateSteamId(steamId) {
@@ -2076,14 +2081,14 @@ var PlayerService = class _PlayerService extends import_koishi5.Service {
2076
2081
  };
2077
2082
  }
2078
2083
  }
2079
- static extendPlayerData(param) {
2084
+ static extendPlayerData(param, dotaconstants) {
2080
2085
  const { playerQuery, playerExtraQuery, genHero, estimateRank } = param;
2081
2086
  const player = playerQuery.player;
2082
2087
  const playerExtra = playerExtraQuery?.player;
2083
2088
  if (player.steamAccount.isAnonymous) {
2084
2089
  for (let index = 0; index < 25; index++) {
2085
2090
  const random = new import_koishi5.Random(() => enhancedSimpleHashToSeed(`${player.steamAccount.id}-${index}`));
2086
- const heroId = random.pick(Object.keys(dotaconstants4.heroes));
2091
+ const heroId = random.pick(Object.keys(dotaconstants.heroes));
2087
2092
  player.matches.push({
2088
2093
  id: 1e9 + index,
2089
2094
  gameMode: "UNKNOWN",
@@ -2100,7 +2105,7 @@ var PlayerService = class _PlayerService extends import_koishi5.Service {
2100
2105
  kills: random.int(0, 20),
2101
2106
  deaths: random.int(0, 20),
2102
2107
  assists: random.int(0, 20),
2103
- hero: { id: heroId, shortName: dotaconstants4.heroes[heroId].name.match(/^npc_dota_hero_(.+)$/)[1] }
2108
+ hero: { id: heroId, shortName: dotaconstants.heroes[heroId].name.match(/^npc_dota_hero_(.+)$/)[1] }
2104
2109
  }
2105
2110
  ]
2106
2111
  });
@@ -2258,8 +2263,8 @@ var CacheService = class extends import_koishi6.Service {
2258
2263
  async getMatchCache(matchId) {
2259
2264
  return this.ctx.cache.get("dt_previous_query_results", String(matchId));
2260
2265
  }
2261
- setMatchCache(matchId, matchQuery, pluginVersion2) {
2262
- this.ctx.cache.set("dt_previous_query_results", String(matchQuery.match.id), { data: matchQuery, pluginVersion: pluginVersion2 }, DAYS_30);
2266
+ setMatchCache(matchId, matchQuery, pluginVersion) {
2267
+ this.ctx.cache.set("dt_previous_query_results", String(matchQuery.match.id), { data: matchQuery, pluginVersion }, DAYS_30);
2263
2268
  }
2264
2269
  markMatchAsSended(matchId) {
2265
2270
  this.ctx.cache.set("dt_sended_match_id", String(matchId), void 0, DAYS_30);
@@ -2388,14 +2393,6 @@ var import_path = __toESM(require("path"));
2388
2393
  var import_axios2 = __toESM(require("axios"));
2389
2394
  var import_https_proxy_agent = require("https-proxy-agent");
2390
2395
  var StratzAPI = class extends import_koishi8.Service {
2391
- constructor(ctx, pluginDir3) {
2392
- super(ctx, "dota2tracker.stratz-api", true);
2393
- this.pluginDir = pluginDir3;
2394
- this.config = ctx.config;
2395
- this.queue = new MiniQueue(ctx, { interval: 200 });
2396
- this.http = import_axios2.default.create({ timeout: 1e4, signal: this.abortController.signal });
2397
- ctx.on("dispose", () => this.dispose());
2398
- }
2399
2396
  static {
2400
2397
  __name(this, "StratzAPI");
2401
2398
  }
@@ -2403,12 +2400,21 @@ var StratzAPI = class extends import_koishi8.Service {
2403
2400
  queue;
2404
2401
  http;
2405
2402
  abortController = new AbortController();
2403
+ graphqlQueriesDir;
2404
+ constructor(ctx, currentDir) {
2405
+ super(ctx, "dota2tracker.stratz-api", true);
2406
+ this.config = ctx.config;
2407
+ this.graphqlQueriesDir = import_path.default.join(currentDir, "queries");
2408
+ this.queue = new MiniQueue(ctx, { interval: 200 });
2409
+ this.http = import_axios2.default.create({ timeout: 15e3, signal: this.abortController.signal });
2410
+ ctx.on("dispose", () => this.dispose());
2411
+ }
2406
2412
  dispose() {
2407
2413
  this.queue.dispose();
2408
2414
  this.abortController.abort();
2409
2415
  }
2410
2416
  async queryGetWeeklyMetaByPosition({ bracketIds }) {
2411
- return this.query("GetWeeklyMetaByPosition", { bracketIds }, (data) => !!data.heroStats);
2417
+ return this.query("GetWeeklyMetaByPosition", { bracketIds }, (data) => !!data?.heroStats);
2412
2418
  }
2413
2419
  async queryPlayerPerformanceForHeroRecommendation({ steamAccountId, recentDateTime }) {
2414
2420
  return this.query(
@@ -2417,7 +2423,7 @@ var StratzAPI = class extends import_koishi8.Service {
2417
2423
  steamAccountId,
2418
2424
  recentDateTime
2419
2425
  },
2420
- (data) => !!data.player
2426
+ (data) => !!data?.player
2421
2427
  );
2422
2428
  }
2423
2429
  async queryPlayersMatchesForDaily(steamAccountIds, seconds) {
@@ -2427,11 +2433,11 @@ var StratzAPI = class extends import_koishi8.Service {
2427
2433
  steamAccountIds,
2428
2434
  seconds
2429
2435
  },
2430
- (data) => !!data.players
2436
+ (data) => !!data?.players
2431
2437
  );
2432
2438
  }
2433
2439
  async queryVerifyingPlayer(steamAccountId) {
2434
- return this.query("VerifyingPlayer", { steamAccountId }, (data) => !!data.player);
2440
+ return this.query("VerifyingPlayer", { steamAccountId }, (data) => !!data?.player);
2435
2441
  }
2436
2442
  async queryPlayerExtraInfo({ steamAccountId, matchCount, heroIds }) {
2437
2443
  return this.query(
@@ -2441,11 +2447,11 @@ var StratzAPI = class extends import_koishi8.Service {
2441
2447
  matchCount,
2442
2448
  heroIds
2443
2449
  },
2444
- (data) => !!data.player
2450
+ (data) => !!data?.player
2445
2451
  );
2446
2452
  }
2447
2453
  async queryPlayersInfoWith10MatchesForGuild({ steamAccountIds }) {
2448
- return this.query("PlayersInfoWith10MatchesForGuild", { steamAccountIds }, (data) => !!data.players);
2454
+ return this.query("PlayersInfoWith10MatchesForGuild", { steamAccountIds }, (data) => !!data?.players);
2449
2455
  }
2450
2456
  async queryPlayerInfoWith25Matches({ steamAccountId, heroIds }) {
2451
2457
  return this.query(
@@ -2454,17 +2460,17 @@ var StratzAPI = class extends import_koishi8.Service {
2454
2460
  steamAccountId,
2455
2461
  heroIds
2456
2462
  },
2457
- (data) => !!data.player
2463
+ (data) => !!data?.player
2458
2464
  );
2459
2465
  }
2460
2466
  async queryPlayersLastMatchRankInfo({ steamAccountIds }) {
2461
- return this.query("PlayersLastmatchRankinfo", { steamAccountIds }, (data) => !!data.players);
2467
+ return this.query("PlayersLastmatchRankinfo", { steamAccountIds }, (data) => !!data?.players);
2462
2468
  }
2463
2469
  async queryConstants(languageTag) {
2464
- return this.query("Constants", { language: this.ctx.dota2tracker.i18n.getGraphqlLanguageTag(languageTag) }, (data) => !!data.constants);
2470
+ return this.query("Constants", { language: this.ctx.dota2tracker.i18n.getGraphqlLanguageTag(languageTag) }, (data) => !!data?.constants);
2465
2471
  }
2466
2472
  async queryMatchInfo(matchId) {
2467
- return this.query("MatchInfo", { matchId }, (data) => !!data.match);
2473
+ return this.query("MatchInfo", { matchId }, (data) => !!data?.match);
2468
2474
  }
2469
2475
  async requestParseMatch(matchId) {
2470
2476
  const response = await this.query("RequestMatchDataAnalysis", {
@@ -2525,7 +2531,7 @@ var StratzAPI = class extends import_koishi8.Service {
2525
2531
  });
2526
2532
  }
2527
2533
  loadGraphqlFile(queryName) {
2528
- return import_fs.default.readFileSync(import_path.default.join(this.pluginDir, "queries", `${queryName}.graphql`), { encoding: "utf-8" }).replace(/[\r\n]+/g, " ");
2534
+ return import_fs.default.readFileSync(import_path.default.join(this.graphqlQueriesDir, `${queryName}.graphql`), { encoding: "utf-8" }).replace(/[\r\n]+/g, " ");
2529
2535
  }
2530
2536
  };
2531
2537
  var MiniQueue = class {
@@ -2592,7 +2598,7 @@ var ValveAPI = class extends import_koishi9.Service {
2592
2598
  constructor(ctx) {
2593
2599
  super(ctx, "dota2tracker.valve-api", true);
2594
2600
  this.config = ctx.config;
2595
- this.http = import_axios3.default.create({ timeout: 1e4, signal: this.abortController.signal, baseURL: this.baseURL });
2601
+ this.http = import_axios3.default.create({ timeout: 15e3, signal: this.abortController.signal, baseURL: this.baseURL });
2596
2602
  ctx.on("dispose", () => this.dispose());
2597
2603
  }
2598
2604
  dispose() {
@@ -2643,7 +2649,6 @@ var import_koishi10 = require("koishi");
2643
2649
  var import_ejs = __toESM(require("ejs"));
2644
2650
  var import_fs2 = __toESM(require("fs"));
2645
2651
  var import_path2 = __toESM(require("path"));
2646
- var dotaconstants5 = __toESM(require("dotaconstants"));
2647
2652
 
2648
2653
  // src/app/common/types.ts
2649
2654
  var ImageType = /* @__PURE__ */ ((ImageType2) => {
@@ -2666,14 +2671,16 @@ var ImageFormat = /* @__PURE__ */ ((ImageFormat2) => {
2666
2671
  // src/app/presentation/image.renderer.ts
2667
2672
  var import_luxon5 = require("luxon");
2668
2673
  var ImageRenderer = class extends import_koishi10.Service {
2669
- constructor(ctx, pluginDir3) {
2674
+ constructor(ctx, currentDir, dotaconstants) {
2670
2675
  super(ctx, "dota2tracker.image", true);
2671
- this.pluginDir = pluginDir3;
2676
+ this.dotaconstants = dotaconstants;
2672
2677
  this.config = ctx.config;
2678
+ this.templateDir = import_path2.default.join(currentDir, "templates");
2673
2679
  }
2674
2680
  static {
2675
2681
  __name(this, "ImageRenderer");
2676
2682
  }
2683
+ templateDir;
2677
2684
  async renderToImageByFile(data, templateName, type, languageTag) {
2678
2685
  const html = await this.generateHTML(data, { source: "FILE", templateName, type }, languageTag);
2679
2686
  return this.ctx.puppeteer.render(html);
@@ -2690,7 +2697,7 @@ var ImageRenderer = class extends import_koishi10.Service {
2690
2697
  data,
2691
2698
  ImageType,
2692
2699
  ImageFormat,
2693
- dotaconstants: dotaconstants5,
2700
+ dotaconstants: this.dotaconstants,
2694
2701
  DateTime: import_luxon5.DateTime,
2695
2702
  $t: /* @__PURE__ */ __name((key, params) => this.ctx.dota2tracker.i18n.$t(languageTag, key, params), "$t"),
2696
2703
  languageTag,
@@ -2701,7 +2708,7 @@ var ImageRenderer = class extends import_koishi10.Service {
2701
2708
  try {
2702
2709
  let html;
2703
2710
  if (template.source === "FILE") {
2704
- const templatePath = import_path2.default.join(this.pluginDir, "template", template.type, `${template.templateName}.ejs`);
2711
+ const templatePath = import_path2.default.join(this.templateDir, template.type, `${template.templateName}.ejs`);
2705
2712
  html = await import_ejs.default.renderFile(templatePath, templateData, {
2706
2713
  strict: false
2707
2714
  });
@@ -2711,7 +2718,7 @@ var ImageRenderer = class extends import_koishi10.Service {
2711
2718
  async: true
2712
2719
  });
2713
2720
  }
2714
- if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync(import_path2.default.join(this.pluginDir, "temp.html"), html);
2721
+ if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync(import_path2.default.resolve(process.cwd(), "temp.html"), html);
2715
2722
  return html;
2716
2723
  } catch (error) {
2717
2724
  this.logger.error(error);
@@ -2721,8 +2728,8 @@ var ImageRenderer = class extends import_koishi10.Service {
2721
2728
  getImageUrl(image, type = "local" /* Local */, format = "png" /* png */) {
2722
2729
  if (type === "local" /* Local */) {
2723
2730
  try {
2724
- if (format === "svg" /* svg */) return import_fs2.default.readFileSync(import_path2.default.join(this.pluginDir, "template", "images", `${image}.svg`));
2725
- const imageData = import_fs2.default.readFileSync(import_path2.default.join(this.pluginDir, "template", "images", `${image}.${format}`));
2731
+ if (format === "svg" /* svg */) return import_fs2.default.readFileSync(import_path2.default.join(this.templateDir, "images", `${image}.svg`));
2732
+ const imageData = import_fs2.default.readFileSync(import_path2.default.join(this.templateDir, "images", `${image}.${format}`));
2726
2733
  const base64Data = imageData.toString("base64");
2727
2734
  return `data:image/png;base64,${base64Data}`;
2728
2735
  } catch (error) {
@@ -3456,20 +3463,25 @@ __name(resolvePlayerAndHandleErrors, "resolvePlayerAndHandleErrors");
3456
3463
  // src/app/commands/hero-of-the-day.command.ts
3457
3464
  var import_luxon10 = require("luxon");
3458
3465
  function registerHeroOfTheDayCommand(ctx) {
3459
- ctx.command("dota2tracker.hero-of-the-day <input_data>").alias("今日英雄").option("days", "-d <value:number>").action(async ({ session, options }, input_data) => {
3460
- const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3461
- if (steamId === null) return;
3462
- const days = clamp(options.days, 1, 180, 30);
3463
- const result = await ctx.dota2tracker.stratzAPI.queryPlayerPerformanceForHeroRecommendation({
3464
- steamAccountId: steamId,
3465
- recentDateTime: import_luxon10.DateTime.now().minus({ days }).toUnixInteger()
3466
- });
3467
- const recommendationPromise = ctx.dota2tracker.player.getHeroRecommendation(steamId, result.player);
3468
- const metaPromise = ctx.dota2tracker.hero.getWeeklyHeroMeta(PlayerService.estimateWeightedRank(result.player));
3469
- const [recommendation, weeklyHeroMeta] = await Promise.all([recommendationPromise, metaPromise]);
3470
- const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3471
- const message = ctx.dota2tracker.messageBuilder.buildHeroOfTheDayMessage(languageTag, recommendation, weeklyHeroMeta);
3472
- return message;
3466
+ const name2 = "hero-of-the-day";
3467
+ ctx.command(`dota2tracker.${name2} <input_data>`).alias("今日英雄").option("days", "-d <value:number>").action(async ({ session, options }, input_data) => {
3468
+ try {
3469
+ const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3470
+ if (steamId === null) return;
3471
+ const days = clamp(options.days, 1, 180, 30);
3472
+ const result = await ctx.dota2tracker.stratzAPI.queryPlayerPerformanceForHeroRecommendation({
3473
+ steamAccountId: steamId,
3474
+ recentDateTime: import_luxon10.DateTime.now().minus({ days }).toUnixInteger()
3475
+ });
3476
+ const recommendationPromise = ctx.dota2tracker.player.getHeroRecommendation(steamId, result.player);
3477
+ const metaPromise = ctx.dota2tracker.hero.getWeeklyHeroMeta(PlayerService.estimateWeightedRank(result.player));
3478
+ const [recommendation, weeklyHeroMeta] = await Promise.all([recommendationPromise, metaPromise]);
3479
+ const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3480
+ const message = ctx.dota2tracker.messageBuilder.buildHeroOfTheDayMessage(languageTag, recommendation, weeklyHeroMeta);
3481
+ return message;
3482
+ } catch (error) {
3483
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3484
+ }
3473
3485
  });
3474
3486
  }
3475
3487
  __name(registerHeroOfTheDayCommand, "registerHeroOfTheDayCommand");
@@ -3477,14 +3489,19 @@ __name(registerHeroOfTheDayCommand, "registerHeroOfTheDayCommand");
3477
3489
  // src/app/commands/query-hero.command.ts
3478
3490
  function registerQueryHeroCommand(ctx) {
3479
3491
  ctx.command("dota2tracker.query-hero <input_data>").option("random", "-r").alias("查询英雄").action(async ({ session, options }, input_data) => {
3480
- if (input_data) {
3481
- await session.send(session.text(".querying_hero"));
3482
- const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3483
- const heroData = await ctx.dota2tracker.hero.getHeroDetails(input_data, languageTag, options.random);
3484
- if (!heroData) return session.text(".not_found");
3485
- const image = await ctx.dota2tracker.image.renderToImageByFile(heroData, ctx.config.template_hero, "hero" /* Hero */, languageTag);
3486
- const message = ctx.dota2tracker.messageBuilder.buildHeroMessage(heroData);
3487
- await session.send(message + image);
3492
+ const name2 = "query-hero";
3493
+ try {
3494
+ if (input_data || options.random) {
3495
+ await session.send(session.text(".querying_hero"));
3496
+ const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3497
+ const heroData = await ctx.dota2tracker.hero.getHeroDetails(input_data, languageTag, options.random);
3498
+ if (!heroData) return session.text(".not_found");
3499
+ const image = await ctx.dota2tracker.image.renderToImageByFile(heroData, ctx.config.template_hero, "hero" /* Hero */, languageTag);
3500
+ const message = ctx.dota2tracker.messageBuilder.buildHeroMessage(heroData);
3501
+ await session.send(message + image);
3502
+ }
3503
+ } catch (error) {
3504
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3488
3505
  }
3489
3506
  });
3490
3507
  }
@@ -3540,25 +3557,40 @@ __name(registerQueryItemCommand, "registerQueryItemCommand");
3540
3557
  // src/app/commands/query-match.command.ts
3541
3558
  function registerQueryMatchCommand(ctx) {
3542
3559
  ctx.command("dota2tracker.query-match <match_id>").alias("查询比赛").option("parse", "-p").option("template", "-t <value:string>").action(async ({ session, options }, match_id) => {
3543
- if (!match_id) return session.text(".empty_input");
3544
- if (!/^\d{1,11}$/.test(match_id)) return session.text(".match_id_invalid");
3545
- await session.send(session.text(".querying_match"));
3546
- return await handleQueryMatchCommand(ctx, ctx.config, session, options, match_id);
3560
+ const name2 = "query-match";
3561
+ try {
3562
+ if (!match_id) return session.text(".empty_input");
3563
+ if (!/^\d{1,11}$/.test(match_id)) return session.text(".match_id_invalid");
3564
+ await session.send(session.text(".querying_match"));
3565
+ return await handleQueryMatchCommand(ctx, ctx.config, session, options, match_id);
3566
+ } catch (error) {
3567
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3568
+ }
3547
3569
  });
3548
3570
  ctx.command("dota2tracker.query-recent-match [input_data]").alias("查询最近比赛").option("parse", "-p").option("template", "-t <value:string>").action(async ({ session, options }, input_data) => {
3549
- const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3550
- if (steamId === null) return;
3551
- session.send(session.text(".querying_match"));
3552
- const lastMatchId = await ctx.dota2tracker.player.getLastMatchId(Number(steamId));
3553
- if (!lastMatchId?.matchId) return session.text(".query_failed");
3554
- if (lastMatchId.isAnonymous) return session.text(".is_anonymous");
3555
- return await handleQueryMatchCommand(ctx, ctx.config, session, options, lastMatchId.matchId);
3571
+ const name2 = "query-recent-match";
3572
+ try {
3573
+ const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3574
+ if (steamId === null) return;
3575
+ session.send(session.text(".querying_match"));
3576
+ let lastMatch;
3577
+ try {
3578
+ lastMatch = await ctx.dota2tracker.player.getLastMatchId(Number(steamId));
3579
+ } catch (error) {
3580
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3581
+ }
3582
+ if (!lastMatch?.id) return session.text(".query_failed");
3583
+ if (lastMatch.isAnonymous) return session.text(".is_anonymous");
3584
+ return await handleQueryMatchCommand(ctx, ctx.config, session, options, lastMatch.id);
3585
+ } catch (error) {
3586
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3587
+ }
3556
3588
  });
3557
3589
  }
3558
3590
  __name(registerQueryMatchCommand, "registerQueryMatchCommand");
3559
3591
  async function handleQueryMatchCommand(ctx, config, session, options, matchId) {
3560
3592
  const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3561
- const result = await ctx.dota2tracker.match.getMatchResult({ matchId: Number(matchId), requestParse: options.parse });
3593
+ const result = await ctx.dota2tracker.match.getMatchResult({ matchId: Number(matchId), waitForParse: options.parse, allowFallback: config.enableOpenDotaFallback });
3562
3594
  if (result.status === "PENDING") {
3563
3595
  const subscriber = ctx.dota2tracker.parsePolling.createSubscriberByCommand(session, languageTag, { templateName: options?.template });
3564
3596
  ctx.dota2tracker.parsePolling.add(result.matchId, [subscriber]);
@@ -3569,7 +3601,6 @@ async function handleQueryMatchCommand(ctx, config, session, options, matchId) {
3569
3601
  const formattedMatchData = await ctx.dota2tracker.match.generateMatchData(result.matchData, languageTag);
3570
3602
  const message = ctx.dota2tracker.messageBuilder.buildMatchMessage(languageTag, formattedMatchData, []);
3571
3603
  const image = await ctx.dota2tracker.image.renderToImageByFile(formattedMatchData, options.template || config.template_match, "match" /* Match */, languageTag);
3572
- await ctx.dota2tracker.image.renderToImageByFile(formattedMatchData, options.template || config.template_match, "match" /* Match */, languageTag);
3573
3604
  return message + image;
3574
3605
  }
3575
3606
  }
@@ -3590,18 +3621,23 @@ __name(registerQueryMembersCommand, "registerQueryMembersCommand");
3590
3621
  // src/app/commands/query-player.command.ts
3591
3622
  function registerQueryPlayerCommand(ctx) {
3592
3623
  ctx.command("dota2tracker.query-player <input_data>").option("hero", "-o <value:string>").alias("查询玩家").action(async ({ session, options }, input_data) => {
3593
- if (session.guild || !session.guild && input_data) {
3594
- const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3595
- if (steamId === null) return;
3596
- session.send(session.text(".querying_player"));
3597
- const heroId = ctx.dota2tracker.i18n.findHeroIdInLocale(options.hero);
3598
- const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3599
- const formattedPlayerData = await ctx.dota2tracker.player.getFormattedPlayerData(steamId, heroId, languageTag);
3600
- const image = await ctx.dota2tracker.image.renderToImageByFile(formattedPlayerData, ctx.config.template_player, "player" /* Player */, languageTag);
3601
- const message = ctx.dota2tracker.messageBuilder.buildPlayerMessage(steamId);
3602
- return message + image;
3603
- } else {
3604
- return session.text("commands.dota2tracker.common.messages.user_not_in_group");
3624
+ const name2 = "query-player";
3625
+ try {
3626
+ if (session.guild || !session.guild && input_data) {
3627
+ const steamId = await resolvePlayerAndHandleErrors(ctx, session, input_data);
3628
+ if (steamId === null) return;
3629
+ session.send(session.text(".querying_player"));
3630
+ const heroId = ctx.dota2tracker.i18n.findHeroIdInLocale(options.hero);
3631
+ const languageTag = await ctx.dota2tracker.i18n.getLanguageTag({ session });
3632
+ const formattedPlayerData = await ctx.dota2tracker.player.getFormattedPlayerData(steamId, heroId, languageTag);
3633
+ const image = await ctx.dota2tracker.image.renderToImageByFile(formattedPlayerData, ctx.config.template_player, "player" /* Player */, languageTag);
3634
+ const message = ctx.dota2tracker.messageBuilder.buildPlayerMessage(steamId);
3635
+ return message + image;
3636
+ } else {
3637
+ return session.text("commands.dota2tracker.common.messages.user_not_in_group");
3638
+ }
3639
+ } catch (error) {
3640
+ handleError(error, ctx.logger(name2), ctx.dota2tracker.i18n, ctx.config);
3605
3641
  }
3606
3642
  });
3607
3643
  }
@@ -3686,7 +3722,7 @@ var OpenDotaAPI = class extends import_koishi15.Service {
3686
3722
  constructor(ctx) {
3687
3723
  super(ctx, "dota2tracker.opendota-api", true);
3688
3724
  this.config = ctx.config;
3689
- this.http = import_axios4.default.create({ timeout: 1e4, signal: this.abortController.signal, baseURL: this.BASE_URL });
3725
+ this.http = import_axios4.default.create({ timeout: 15e3, signal: this.abortController.signal, baseURL: this.BASE_URL });
3690
3726
  ctx.on("dispose", () => this.dispose());
3691
3727
  }
3692
3728
  dispose() {
@@ -3736,14 +3772,14 @@ var OpenDotaAPI = class extends import_koishi15.Service {
3736
3772
 
3737
3773
  // src/app/core/opendota.adapter.ts
3738
3774
  var import_koishi16 = require("koishi");
3739
- var dotaconstants6 = __toESM(require("dotaconstants"));
3740
3775
  var OpenDotaAdapter = class extends import_koishi16.Service {
3776
+ constructor(ctx, dotaconstants) {
3777
+ super(ctx, "dota2tracker.opendota-adapter", true);
3778
+ this.dotaconstants = dotaconstants;
3779
+ }
3741
3780
  static {
3742
3781
  __name(this, "OpenDotaAdapter");
3743
3782
  }
3744
- constructor(ctx) {
3745
- super(ctx, "dota2tracker.opendota-adapter", true);
3746
- }
3747
3783
  transform(_match) {
3748
3784
  determinePlayerPositions(_match);
3749
3785
  const players = [];
@@ -3791,9 +3827,9 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3791
3827
  steamAccount: { name: _player.personaname, seasonRank: _player.rank_tier, seasonLeaderboardRank: null },
3792
3828
  hero: {
3793
3829
  id: _player.hero_id,
3794
- name: dotaconstants6.heroes[_player.hero_id].name,
3795
- shortName: dotaconstants6.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1],
3796
- facets: [...dotaconstants6.hero_abilities[dotaconstants6.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
3830
+ name: this.dotaconstants.heroes[_player.hero_id].name,
3831
+ shortName: this.dotaconstants.heroes[_player.hero_id].name.match(/^npc_dota_hero_(.+)$/)[1],
3832
+ facets: [...this.dotaconstants.hero_abilities[this.dotaconstants.heroes[_player.hero_id].name].facets.map((f) => ({ id: -1, name: f.name }))]
3797
3833
  },
3798
3834
  dotaPlus: null,
3799
3835
  stats: {
@@ -3824,7 +3860,7 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3824
3860
  disableCount: 0
3825
3861
  }
3826
3862
  },
3827
- itemPurchases: _player.purchase_log.map((p) => ({ time: p.time, itemId: dotaconstants6.items[p.key].id }))
3863
+ itemPurchases: _player.purchase_log.map((p) => ({ time: p.time, itemId: this.dotaconstants.items[p.key].id }))
3828
3864
  },
3829
3865
  additionalUnit: null
3830
3866
  };
@@ -3853,8 +3889,8 @@ var OpenDotaAdapter = class extends import_koishi16.Service {
3853
3889
  const match = {
3854
3890
  id: _match.match_id,
3855
3891
  didRadiantWin: _match.radiant_win,
3856
- lobbyType: convertLobbyType(_match.lobby_type),
3857
- gameMode: convertGameMode(_match.game_mode),
3892
+ lobbyType: convertLobbyType(_match.lobby_type, this.dotaconstants),
3893
+ gameMode: convertGameMode(_match.game_mode, this.dotaconstants),
3858
3894
  regionId: _match.region,
3859
3895
  parsedDateTime: _match.start_time + _match.duration,
3860
3896
  startDateTime: _match.start_time,
@@ -3939,7 +3975,7 @@ function convertPosition(openDotaPosition) {
3939
3975
  }
3940
3976
  }
3941
3977
  __name(convertPosition, "convertPosition");
3942
- function convertLobbyType(openDotaLobbyType) {
3978
+ function convertLobbyType(openDotaLobbyType, dotaconstants) {
3943
3979
  const map = {
3944
3980
  lobby_type_normal: "UNRANKED" /* Unranked */,
3945
3981
  lobby_type_practice: "PRACTICE" /* Practice */,
@@ -3956,11 +3992,11 @@ function convertLobbyType(openDotaLobbyType) {
3956
3992
  lobby_type_new_player: "COOP_VS_BOTS" /* CoopVsBots */,
3957
3993
  lobby_type_featured: "EVENT" /* Event */
3958
3994
  };
3959
- return map[dotaconstants6.lobby_type[openDotaLobbyType].name] || "EVENT" /* Event */;
3995
+ return map[dotaconstants.lobby_type[openDotaLobbyType].name] || "EVENT" /* Event */;
3960
3996
  }
3961
3997
  __name(convertLobbyType, "convertLobbyType");
3962
- function convertGameMode(openDotaGameModeId) {
3963
- const gameModeName = dotaconstants6.game_mode[openDotaGameModeId]?.name;
3998
+ function convertGameMode(openDotaGameModeId, dotaconstants) {
3999
+ const gameModeName = dotaconstants.game_mode[openDotaGameModeId]?.name;
3964
4000
  switch (gameModeName) {
3965
4001
  case "game_mode_all_pick":
3966
4002
  return "ALL_PICK" /* AllPick */;
@@ -4178,7 +4214,7 @@ var globRequire_locales_schema_yml = __glob({
4178
4214
  });
4179
4215
 
4180
4216
  // src/config.ts
4181
- var pluginDir = import_path4.default.resolve(__dirname, "..");
4217
+ var templateDir = import_path4.default.join(__dirname, "templates");
4182
4218
  var allI18nConfigs = Object.fromEntries(Object.keys(LanguageTags).map((lang) => [lang, globRequire_locales_schema_yml(`./locales/${lang}.schema.yml`)._config]));
4183
4219
  var Config = import_koishi17.Schema.intersect([
4184
4220
  import_koishi17.Schema.intersect([
@@ -4249,9 +4285,9 @@ var Config = import_koishi17.Schema.intersect([
4249
4285
  ]).i18n(getI18n("report"))
4250
4286
  ]),
4251
4287
  import_koishi17.Schema.object({
4252
- template_match: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(pluginDir, "template", "match"))]).default("match_1"),
4253
- template_player: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(pluginDir, "template", "player"))]).default("player_1"),
4254
- template_hero: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(pluginDir, "template", "hero"))]).default("hero_1"),
4288
+ template_match: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(templateDir, "match"))]).default("match_1"),
4289
+ template_player: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(templateDir, "player"))]).default("player_1"),
4290
+ template_hero: import_koishi17.Schema.union([...readDirectoryFilesSync(import_path4.default.join(templateDir, "hero"))]).default("hero_1"),
4255
4291
  playerRankEstimate: import_koishi17.Schema.boolean().default(true),
4256
4292
  templateFonts: import_koishi17.Schema.array(String).default([]).role("table")
4257
4293
  }).i18n(getI18n("template"))
@@ -4285,16 +4321,18 @@ var inject = {
4285
4321
  required: ["database", "puppeteer", "cache"],
4286
4322
  optional: ["cron", "console"]
4287
4323
  };
4288
- var pluginDir2 = import_path5.default.resolve(__dirname, "..");
4289
- var pluginVersion = require(import_path5.default.join(pluginDir2, "package.json")).version;
4290
4324
  async function apply(ctx, config) {
4325
+ const lib = await import("dotaconstants");
4326
+ const dotaconstants = lib.default || lib;
4291
4327
  const logger = ctx.logger("dota2tracker");
4328
+ const currentDir = import_path5.default.resolve(__dirname);
4329
+ const pluginVersion = require(import_path5.default.join(currentDir, "..", "package.json")).version;
4292
4330
  ctx.dota2tracker = {};
4293
- ctx.dota2tracker.i18n = new I18NService(ctx);
4294
- ctx.dota2tracker.image = new ImageRenderer(ctx, pluginDir2);
4331
+ ctx.dota2tracker.i18n = new I18NService(ctx, dotaconstants);
4332
+ ctx.dota2tracker.image = new ImageRenderer(ctx, currentDir, dotaconstants);
4295
4333
  ctx.dota2tracker.messageBuilder = new MessageBuilder(ctx);
4296
- ctx.dota2tracker.match = new MatchService(ctx, pluginVersion);
4297
- ctx.dota2tracker.player = new PlayerService(ctx);
4334
+ ctx.dota2tracker.match = new MatchService(ctx, pluginVersion, dotaconstants);
4335
+ ctx.dota2tracker.player = new PlayerService(ctx, dotaconstants);
4298
4336
  if (ctx.cron) {
4299
4337
  ctx.dota2tracker.matchWatcher = new MatchWatcherTask(ctx);
4300
4338
  ctx.dota2tracker.parsePolling = new ParsePollingTask(ctx);
@@ -4306,15 +4344,15 @@ async function apply(ctx, config) {
4306
4344
  } else {
4307
4345
  logger.info(ctx.dota2tracker.i18n.gt("dota2tracker.logger.cron_not_enabled"));
4308
4346
  }
4309
- ctx.dota2tracker.hero = new HeroService(ctx);
4347
+ ctx.dota2tracker.hero = new HeroService(ctx, dotaconstants);
4310
4348
  ctx.dota2tracker.item = new ItemService(ctx);
4311
4349
  ctx.dota2tracker.cache = new CacheService(ctx);
4312
4350
  ctx.dota2tracker.database = new DatabaseService(ctx);
4313
4351
  ctx.dota2tracker.valveAPI = new ValveAPI(ctx);
4314
- ctx.dota2tracker.stratzAPI = new StratzAPI(ctx, pluginDir2);
4352
+ ctx.dota2tracker.stratzAPI = new StratzAPI(ctx, currentDir);
4315
4353
  if (config.enableOpenDotaFallback) {
4316
4354
  ctx.dota2tracker.opendotaAPI = new OpenDotaAPI(ctx);
4317
- ctx.dota2tracker.opendotaAdapter = new OpenDotaAdapter(ctx);
4355
+ ctx.dota2tracker.opendotaAdapter = new OpenDotaAdapter(ctx, dotaconstants);
4318
4356
  }
4319
4357
  ctx.dota2tracker = ctx.dota2tracker;
4320
4358
  usage = await ctx.dota2tracker.i18n.generateUsage();
@@ -4327,7 +4365,7 @@ async function apply(ctx, config) {
4327
4365
  registerQueryHeroCommand(ctx);
4328
4366
  registerQueryItemCommand(ctx);
4329
4367
  registerHeroOfTheDayCommand(ctx);
4330
- if (config.enableConsole) registerConsolePage(ctx);
4368
+ if (ctx.console && config.enableConsole) registerConsolePage(ctx);
4331
4369
  }
4332
4370
  __name(apply, "apply");
4333
4371
  // Annotate the CommonJS export names for ESM import in node: