@sjtdev/koishi-plugin-dota2tracker 1.3.0-pre.5 → 1.3.0

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/lib/index.js CHANGED
@@ -35,11 +35,26 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
35
35
  ));
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
 
38
+ // src/locales/en-US.schema.yml
39
+ var require_en_US_schema = __commonJS({
40
+ "src/locales/en-US.schema.yml"(exports2, module2) {
41
+ module2.exports = { _config: { base: { $desc: "Basic Settings", STRATZ_API_TOKEN: "Required. API TOKEN from stratz.com, available at https://stratz.com/api.", dataParsingTimeoutMinutes: "Time to wait for match data parsing (in minutes). If the data parsing time exceeds the waiting time, the report will be generated directly without waiting for the parsing to complete.", urlInMessageType: { $desc: "Include links in messages, <br/>please select the message type:", $inner: ["Include stratz match page link in match query and report messages", "Include stratz player page link in player information query messages", "Include Dota Encyclopedia hero page link in hero data query messages"] } }, rank: { rankBroadSwitch: "Rank change broadcast", rankBroadStar: "Star change broadcast", rankBroadLeader: "Leaderboard rank change broadcast", rankBroadFun: "Fun broadcast template" }, report: { $desc: "Summary Settings", dailyReportSwitch: "Daily Report Function", dailyReportHours: "Daily report time in hours", dailyReportShowCombi: "Show combinations in daily report", weeklyReportSwitch: "Weekly Report Function", weeklyReportDayHours: "Weekly report published on (day) at (hour)", weeklyReportShowCombi: "Show combinations in weekly report" }, template: { $desc: "Template Settings", template_match: "Template used to generate match information images, see https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki for template display.", template_player: "Template used to generate player information images. (Currently only one template available)", template_hero: "Template used to generate hero information images. (Currently only one template available)" } } };
42
+ }
43
+ });
44
+
45
+ // src/locales/zh-CN.schema.yml
46
+ var require_zh_CN_schema = __commonJS({
47
+ "src/locales/zh-CN.schema.yml"(exports2, module2) {
48
+ module2.exports = { _config: { base: { $desc: "基础设置", STRATZ_API_TOKEN: "※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。", dataParsingTimeoutMinutes: "等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。", urlInMessageType: { $desc: "在消息中附带链接,<br/>请选择消息类型:", $inner: ["在查询比赛与战报消息中附带stratz比赛页面链接", "在查询玩家信息消息中附带stratz玩家页面链接", "在查询英雄数据消息中附带刀塔百科对应英雄页面链接"] } }, rank: { rankBroadSwitch: "段位变动播报", rankBroadStar: "星级变动播报", rankBroadLeader: "冠绝名次变动播报", rankBroadFun: "整活播报模板" }, report: { $desc: "总结设置", dailyReportSwitch: "日报功能", dailyReportHours: "日报时间小时", dailyReportShowCombi: "日报是否显示组合", weeklyReportSwitch: "周报功能", weeklyReportDayHours: "周报发布于周(几)的(几)点", weeklyReportShowCombi: "周报是否显示组合" }, template: { $desc: "模板设置", template_match: "生成比赛信息图片使用的模板,见 https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki 有模板展示。", template_player: "生成玩家信息图片使用的模板。(目前仅有一张模板)", template_hero: "生成英雄信息图片使用的模板。(目前仅有一张模板)" } } };
49
+ }
50
+ });
51
+
38
52
  // src/locales/en-US.constants.json
39
53
  var require_en_US_constants = __commonJS({
40
54
  "src/locales/en-US.constants.json"(exports2, module2) {
41
55
  module2.exports = {
42
56
  dota2tracker: {
57
+ usage: "DOTA2Bot plugin - provides the functionality to automatically track the latest matches of group members (requires group members to bind), as well as a series of query functions. \n[Localization/dota2tracker](../../locales/dota2tracker) allows customization of hero aliases and position nicknames, etc. \n**For more information, please visit the [plugin homepage](https://sjtdev.github.io/koishi-plugin-dota2tracker/) and [changelog](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/changelog.md).**",
43
58
  template: {
44
59
  game_modes: {
45
60
  NONE: "None",
@@ -85,6 +100,7 @@ var require_en_US_constants = __commonJS({
85
100
  NEW_PLAYER_POOL: "New Player Pool"
86
101
  },
87
102
  regions: {
103
+ "0": "Unknown",
88
104
  "1": "US West",
89
105
  "2": "US East",
90
106
  "3": "Europe West",
@@ -303,9 +319,10 @@ var require_zh_CN_constants = __commonJS({
303
319
  "src/locales/zh-CN.constants.json"(exports2, module2) {
304
320
  module2.exports = {
305
321
  dota2tracker: {
322
+ usage: "DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。 \n[本地化/dota2tracker](../../locales/dota2tracker)可以自定义英雄别名和位置代称等文本内容 \n**更多信息请进入[插件主页](https://sjtdev.github.io/koishi-plugin-dota2tracker/)与[更新日志](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/changelog.md)查看。**",
306
323
  template: {
307
324
  game_modes: {
308
- NONE: "",
325
+ NONE: "未知",
309
326
  ALL_PICK: "全英雄选择",
310
327
  CAPTAINS_MODE: "队长模式",
311
328
  RANDOM_DRAFT: "随机征召",
@@ -348,6 +365,7 @@ var require_zh_CN_constants = __commonJS({
348
365
  NEW_PLAYER_POOL: ""
349
366
  },
350
367
  regions: {
368
+ "0": "未知",
351
369
  "1": "US WEST",
352
370
  "2": "US EAST",
353
371
  "3": "EUROPE",
@@ -564,42 +582,42 @@ var require_zh_CN_constants = __commonJS({
564
582
  // src/locales/en-US.command.yml
565
583
  var require_en_US_command = __commonJS({
566
584
  "src/locales/en-US.command.yml"(exports2, module2) {
567
- module2.exports = { commands: { dota2tracker: { subscribe: { description: "After subscribing, players need to bind their Steam ID to this group.", usage: "After subscribing, players need to bind their Steam ID to this group. BOT will subscribe to the new game data of bound players in this group. After the STRATZ game analysis is completed, the game data will be generated into a picture battle report and published to this group.", messages: { subscribe_success: "Subscription successful.", subscribed: "This Channel has been subscribed, no need to subscribe again." } }, unsubscribe: { description: "Unsubscribe from this group.", messages: { unsubscribe_success: "Unsubscription successful.", not_subscribed: "This Channel has not been subscribed yet, so there is no need to unsubscribe." } }, bind: { description: "Bind your SteamID and optionally set a nickname.", usage: "Bind your SteamID to your account. If the group is subscribed, your new match data will be posted in the group in real-time.", examples: 'bind 123456789\nbind 123456789 John\nbind 123456789 "John Doe"', messages: { steam_id_invalid: "Invalid SteamID.", bind_success: "Binding successful,\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", bind_failed: "Binding failed, {0}", reason_without_match: "Invalid SteamID or no matches found.", reason_fetch_failed: "Poor network conditions or other reasons prevented the verification of the SteamID. Please try again later.", already_binded: "You are already bound, no need to bind again.\nHere is your personal information:\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", nick_name_too_long: "Nickname is too long, please limit it to 20 characters or less. (It can also be left blank)" } }, unbind: { description: "Unbind your personal information.", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Change the nickname set during binding.", examples: 'rename John\nrename "John Doe"', messages: { rename_success: "Rename successful, now you are called {nick_name}.", empty_input: "Please enter your nickname.", not_binded: "Please bind first, you can set a nickname during binding.", nick_name_too_long: "Nickname is too long, please limit it to 20 characters." } }, "query-members": { description: "Query the players bound in this group.", messages: { no_members: "No players bound in this group.", query_failed: "Failed to query group members." } }, "query-match": { description: "Query the match data of the specified match ID and generate a picture.", examples: "query-match 1234567890", messages: { empty_input: "Please enter the match ID.", match_id_invalid: "Invalid match ID.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get match data." } }, "query-recent-match": { description: "Query the most recent match data and generate a picture.", usage: "Query the most recent match data of the specified player and generate a picture.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-recent-match\nquery-recent-match 123456789\nquery-recent-match John", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [-bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-player": { description: "Query the player's personal information, optionally specify a hero.", options: { hero: "Query the player's usage of the specified hero (same as querying a hero, can use nickname or ID)" }, usage: "Query the personal information of the specified player and generate a picture, optionally specify a hero.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-player 123456789\nquery-player John\nquery-player John --hero Anti-Mage\nquery-player John -o Anti-Mage", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [-bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-hero": { description: "Query hero skills/stats information.", options: { random: "Randomly select a hero." }, usage: "Query the hero's skill descriptions and various stats, generate a picture.\nThe parameter can be the hero's ID, name, or common nickname.", examples: "query-hero 15\nquery-hero Razor\nquery-hero -r", messages: { not_found: "Hero not found, please confirm and re-enter.", querying_hero: "Retrieving hero data, please wait...", query_failed: "Failed to get hero data.", empty_input: "Please enter a parameter." } } } } };
585
+ module2.exports = { commands: { dota2tracker: { subscribe: { description: "After subscribing, players need to bind their Steam ID to this group.", usage: "After subscribing, players need to bind their Steam ID to this group. BOT will subscribe to the new game data of bound players in this group. After the STRATZ game analysis is completed, the game data will be generated into a picture battle report and published to this group.", messages: { subscribe_success: "Subscription successful.", subscribed: "This Channel has been subscribed, no need to subscribe again." } }, unsubscribe: { description: "Unsubscribe from this group.", messages: { unsubscribe_success: "Unsubscription successful.", not_subscribed: "This Channel has not been subscribed yet, so there is no need to unsubscribe." } }, bind: { description: "Bind your SteamID and optionally set a nickname.", usage: "Bind your SteamID to your account. If the group is subscribed, your new match data will be posted in the group in real-time.", examples: 'bind 123456789\nbind 123456789 John\nbind 123456789 "John Doe"', messages: { steam_id_invalid: "Invalid SteamID.", bind_success: "Binding successful,\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", bind_failed: "Binding failed, {0}", reason_without_match: "Invalid SteamID or no matches found.", reason_fetch_failed: "Poor network conditions or other reasons prevented the verification of the SteamID. Please try again later.", already_binded: "You are already bound, no need to bind again.\nHere is your personal information:\nID: {userId}\nNickname: {nickName}\nSteamID: {steamId}", nick_name_too_long: "Nickname is too long, please limit it to 20 characters or less. (It can also be left blank)" } }, unbind: { description: "Unbind your personal information.", messages: { unbind_success: "Unbinding successful.", not_binded: "Not bound, no need to unbind." } }, rename: { description: "Change the nickname set during binding.", examples: 'rename John\nrename "John Doe"', messages: { rename_success: "Rename successful, now you are called {nick_name}.", empty_input: "Please enter your nickname.", not_binded: "Please bind first, you can set a nickname during binding.", nick_name_too_long: "Nickname is too long, please limit it to 20 characters." } }, "query-members": { description: "Query the players bound in this group.", messages: { no_members: "No players bound in this group.", query_failed: "Failed to query group members." } }, "query-match": { description: "Query the match data of the specified match ID and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, examples: "query-match 1234567890\nquery-match 1234567890 -p\nquery-match 1234567890 --parse", messages: { empty_input: "Please enter the match ID.", match_id_invalid: "Invalid match ID.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get match data.", waiting_for_parse: "Match data has not been parsed yet, a parse request has been sent to the server. The battle report will be sent once parsing is complete or times out." } }, "query-recent-match": { description: "Query the most recent match data and generate a picture.", options: { parse: "Whether to wait for match data parsing" }, usage: "Query the most recent match data of the specified player and generate a picture.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-recent-match\nquery-recent-match 123456789\nquery-recent-match John\nquery-recent-match 123456789 -p\nquery-recent-match John --parse", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [-bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_match: "Searching for match details, please wait...", query_failed: "Failed to get the player's recent match.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-player": { description: "Query the player's personal information, optionally specify a hero.", options: { hero: "Query the player's usage of the specified hero (same as querying a hero, can use nickname or ID)" }, usage: "Query the personal information of the specified player and generate a picture, optionally specify a hero.\nThe parameter can be the player's SteamID or the nickname of a player bound in this group. If no parameter is provided, it will try to query the SteamID of the command caller.", examples: "query-player\nquery-player 123456789\nquery-player John\nquery-player John --hero Anti-Mage\nquery-player John -o Anti-Mage", messages: { not_binded: "By default, it tries to find your information from the bound SteamID players, but it seems you are not bound.\nPlease bind your SteamID in this group. (You can enter [bind -h] for help)\nOr follow the command with the SteamID or nickname of the player you want to query.", steam_id_invalid: "Invalid SteamID and the player was not found in this group.", querying_player: "Retrieving player data, please wait...", query_failed: "Failed to get player information.", not_in_group: "Command failed.\nCurrently not in a group chat, you must provide the specified player's SteamID." } }, "query-hero": { description: "Query hero skills/stats information.", options: { random: "Randomly select a hero." }, usage: "Query the hero's skill descriptions and various stats, generate a picture.\nThe parameter can be the hero's ID, name, or common nickname.", examples: "query-hero 15\nquery-hero Razor\nquery-hero -r", messages: { not_found: "Hero not found, please confirm and re-enter.", querying_hero: "Retrieving hero data, please wait...", query_failed: "Failed to get hero data.", empty_input: "Please enter a parameter." } } } } };
568
586
  }
569
587
  });
570
588
 
571
589
  // src/locales/en-US.template.yml
572
590
  var require_en_US_template = __commonJS({
573
591
  "src/locales/en-US.template.yml"(exports2, module2) {
574
- module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)" } } };
592
+ module2.exports = { dota2tracker: { template: { radiant: "Radiant", dire: "Dire", won: "Won", lost: "Lost", match_id_: "Match ID: {0}", game_mode_: "Mode: {0}", start_time_: "Start Time: {0}", end_time_: "End Time: {0}", pick_order: "#{0}", random: "R", hero_damage_: "Damage: {0}", building_damage_: "Building: {0}", damage_received_: "Received: {0}", lasthit_: "LastHit: {0}", deny_: "Deny: {0}", "lh/dn_": "LH/DN: {0}", GPM: "GPM", XPM: "XPM", heal_: "Heal: {0}", crowd_control_duration_: "CCD: {0}", "GPM/XPM_": "GPM/XPM: {0}", lane: "Lane", lane_: "Lane: ", lane_advantage: "Lane +", lane_disadvantage: "Lane -", lane_jungle: "Jungle", lane_stomp: "Lane+++", lane_stomped: "Lane---", lane_tie: "Lane ==", analysis_successful: "Analysis successful", analysis_incomplete: "Analysis incomplete", kill: "Kill", kill_contribution_: "KC: {0}", position: "Position", position_: "Position: ", position_1: "Carry", position_2: "Mid", position_3: "OffLane", position_4: "Softsup", position_5: "Hardsup", dire_won: "Dire Won", radiant_won: "Radiant Won", total_damage: "Damage", total_experience: "Exp.", total_gold: "Gold", region_: "Region: {0}", duration_: "Duration: {0}", position_undefined: "?", top10_: "Top 10 Heroes by Matches: ", match_count_: "Matches: ", last25matches_: "Last 25 Matches: ", winrate_: "Winrate: ", imp_: "IMP: ", lane_advantage_rate_: "Lane Advantage Rate: ", hero: "Hero", all_matches_: "All Matches: ", match_count: "Matches", winrate: "Winrate", imp: "IMP", win_count: "Wins", lose_count: "Losses", recently_heroes: "Heroes used more than once recently: ", recently_positions: "Performance in the last 25 matches across all positions: ", winning_streak: "Winning Streak", losing_streak: "Losing Streak", id: "ID", mode: "Mode", kda_kc: "KDA(KC)", time: "Time", duration: "Duration", rank: "Rank", un_parsed: "(Unparsed)", combined_win_loss_summary: "Combined Win/Loss Summary: ", yesterdays_summary: "Yesterday's Summary", last_weeks_summary: "Last Week's Summary", report_won: "W", report_lost: "L", report_winrate: "WR" } } };
575
593
  }
576
594
  });
577
595
 
578
596
  // src/locales/en-US.yml
579
597
  var require_en_US = __commonJS({
580
598
  "src/locales/en-US.yml"(exports2, module2) {
581
- module2.exports = { dota2tracker: { heroes_nicknames: { "0": 'Please strictly follow the format of "", "" when filling out, if the format is incorrect, only the default name of the hero will be used. The default name of the hero may be omitted.', "1": '"Anti-Mage"', "2": '"Axe"', "3": '"Bane"', "4": '"Bloodseeker"', "5": '"Crystal Maiden"', "6": '"Drow Ranger"', "7": '"Earthshaker"', "8": '"Juggernaut"', "9": '"Mirana"', "10": '"Morphling"', "11": '"Shadow Fiend"', "12": '"Phantom Lancer"', "13": '"Puck"', "14": '"Pudge"', "15": '"Razor"', "16": '"Sand King"', "17": '"Storm Spirit"', "18": '"Sven"', "19": '"Tiny"', "20": '"Vengeful Spirit"', "21": '"Windranger"', "22": '"Zeus"', "23": '"Kunkka"', "25": '"Lina"', "26": '"Lion"', "27": '"Shadow Shaman"', "28": '"Slardar"', "29": '"Tidehunter"', "30": '"Witch Doctor"', "31": '"Lich"', "32": '"Riki"', "33": '"Enigma"', "34": '"Tinker"', "35": '"Sniper"', "36": '"Necrophos"', "37": '"Warlock"', "38": '"Beastmaster"', "39": '"Queen of Pain"', "40": '"Venomancer"', "41": '"Faceless Void"', "42": '"Wraith King"', "43": '"Death Prophet"', "44": '"Phantom Assassin"', "45": '"Pugna"', "46": '"Templar Assassin"', "47": '"Viper"', "48": '"Luna"', "49": '"Dragon Knight"', "50": '"Dazzle"', "51": '"Clockwerk"', "52": '"Leshrac"', "53": `"Nature's Prophet"`, "54": '"Lifestealer"', "55": '"Dark Seer"', "56": '"Clinkz"', "57": '"Omniknight"', "58": '"Enchantress"', "59": '"Huskar"', "60": '"Night Stalker"', "61": '"Broodmother"', "62": '"Bounty Hunter"', "63": '"Weaver"', "64": '"Jakiro"', "65": '"Batrider"', "66": '"Chen"', "67": '"Spectre"', "68": '"Ancient Apparition"', "69": '"Doom"', "70": '"Ursa"', "71": '"Spirit Breaker"', "72": '"Gyrocopter"', "73": '"Alchemist"', "74": '"Invoker"', "75": '"Silencer"', "76": '"Outworld Devourer"', "77": '"Lycan"', "78": '"Brewmaster"', "79": '"Shadow Demon"', "80": '"Lone Druid"', "81": '"Chaos Knight"', "82": '"Meepo"', "83": '"Treant Protector"', "84": '"Ogre Magi"', "85": '"Undying"', "86": '"Rubick"', "87": '"Disruptor"', "88": '"Nyx Assassin"', "89": '"Naga Siren"', "90": '"Keeper of the Light"', "91": '"Io"', "92": '"Visage"', "93": '"Slark"', "94": '"Medusa"', "95": '"Troll Warlord"', "96": '"Centaur Warrunner"', "97": '"Magnus"', "98": '"Timbersaw"', "99": '"Bristleback"', "100": '"Tusk"', "101": '"Skywrath Mage"', "102": '"Abaddon"', "103": '"Elder Titan"', "104": '"Legion Commander"', "105": '"Techies"', "106": '"Ember Spirit"', "107": '"Earth Spirit"', "108": '"Underlord"', "109": '"Terrorblade"', "110": '"Phoenix"', "111": '"Oracle"', "112": '"Winter Wyvern"', "113": '"Arc Warden"', "114": '"Monkey King"', "119": '"Dark Willow"', "120": '"Pangolier"', "121": '"Grimstroke"', "123": '"Hoodwink"', "126": '"Void Spirit"', "128": '"Snapfire"', "129": '"Mars"', "131": '"Ring Master"', "135": '"Dawnbreaker"', "136": '"Marci"', "137": '"Primal Beast"', "138": '"Muerta"', "145": '"Kez"' }, broadcast: { WIN_NEGATIVE: `"Won the match by sheer luck", "Won the match by a stroke of bad luck", "Coasted to victory", "Didn't even show up for the team fight, but my teammates won 4v5"`, WIN_POSITIVE: '"Led the team to victory", "Dominated the opponents and secured the win", "Carried the game to victory", "Treated the opponents like pigs and won", "Won again; this game is just so monotonous and dull", "Simply achieved a win in the match"', LOSE_NEGATIVE: '"Got crushed and lost the match", "Lost the match miserably", "Got my head knocked sideways and lost the match with a blown mindset", "Went fishing but got eaten by the fish, lost the match", "Played terribly", "Simply suffered a loss in the match"', LOSE_POSITIVE: `"Lost the match with no way to turn it around", "Gave it my all, but still lost the match", "Though we lost, we still have honor", "Couldn't carry my teammates, lost the match", "Lost again, it hurts; I'd rather it be me losing"`, message: "{name}'s {hero_name} {comment}.\nKDA: {kda}, GPM/XPM: {gpm_xpm}, Last Hits/Denies: {lh_dn}, Damage/Tower Damage: {damage}, Kill/Death Contribution Rate: {kc_dc}" } } };
599
+ module2.exports = { dota2tracker: { heroes_nicknames: { "0": 'Please strictly follow the format of "", "" when filling out, if the format is incorrect, only the default name of the hero will be used. The default name of the hero may be omitted.', "1": '"Anti-Mage"', "2": '"Axe"', "3": '"Bane"', "4": '"Bloodseeker"', "5": '"Crystal Maiden"', "6": '"Drow Ranger"', "7": '"Earthshaker"', "8": '"Juggernaut"', "9": '"Mirana"', "10": '"Morphling"', "11": '"Shadow Fiend"', "12": '"Phantom Lancer"', "13": '"Puck"', "14": '"Pudge"', "15": '"Razor"', "16": '"Sand King"', "17": '"Storm Spirit"', "18": '"Sven"', "19": '"Tiny"', "20": '"Vengeful Spirit"', "21": '"Windranger"', "22": '"Zeus"', "23": '"Kunkka"', "25": '"Lina"', "26": '"Lion"', "27": '"Shadow Shaman"', "28": '"Slardar"', "29": '"Tidehunter"', "30": '"Witch Doctor"', "31": '"Lich"', "32": '"Riki"', "33": '"Enigma"', "34": '"Tinker"', "35": '"Sniper"', "36": '"Necrophos"', "37": '"Warlock"', "38": '"Beastmaster"', "39": '"Queen of Pain"', "40": '"Venomancer"', "41": '"Faceless Void"', "42": '"Wraith King"', "43": '"Death Prophet"', "44": '"Phantom Assassin"', "45": '"Pugna"', "46": '"Templar Assassin"', "47": '"Viper"', "48": '"Luna"', "49": '"Dragon Knight"', "50": '"Dazzle"', "51": '"Clockwerk"', "52": '"Leshrac"', "53": `"Nature's Prophet"`, "54": '"Lifestealer"', "55": '"Dark Seer"', "56": '"Clinkz"', "57": '"Omniknight"', "58": '"Enchantress"', "59": '"Huskar"', "60": '"Night Stalker"', "61": '"Broodmother"', "62": '"Bounty Hunter"', "63": '"Weaver"', "64": '"Jakiro"', "65": '"Batrider"', "66": '"Chen"', "67": '"Spectre"', "68": '"Ancient Apparition"', "69": '"Doom"', "70": '"Ursa"', "71": '"Spirit Breaker"', "72": '"Gyrocopter"', "73": '"Alchemist"', "74": '"Invoker"', "75": '"Silencer"', "76": '"Outworld Devourer"', "77": '"Lycan"', "78": '"Brewmaster"', "79": '"Shadow Demon"', "80": '"Lone Druid"', "81": '"Chaos Knight"', "82": '"Meepo"', "83": '"Treant Protector"', "84": '"Ogre Magi"', "85": '"Undying"', "86": '"Rubick"', "87": '"Disruptor"', "88": '"Nyx Assassin"', "89": '"Naga Siren"', "90": '"Keeper of the Light"', "91": '"Io"', "92": '"Visage"', "93": '"Slark"', "94": '"Medusa"', "95": '"Troll Warlord"', "96": '"Centaur Warrunner"', "97": '"Magnus"', "98": '"Timbersaw"', "99": '"Bristleback"', "100": '"Tusk"', "101": '"Skywrath Mage"', "102": '"Abaddon"', "103": '"Elder Titan"', "104": '"Legion Commander"', "105": '"Techies"', "106": '"Ember Spirit"', "107": '"Earth Spirit"', "108": '"Underlord"', "109": '"Terrorblade"', "110": '"Phoenix"', "111": '"Oracle"', "112": '"Winter Wyvern"', "113": '"Arc Warden"', "114": '"Monkey King"', "119": '"Dark Willow"', "120": '"Pangolier"', "121": '"Grimstroke"', "123": '"Hoodwink"', "126": '"Void Spirit"', "128": '"Snapfire"', "129": '"Mars"', "131": '"Ring Master"', "135": '"Dawnbreaker"', "136": '"Marci"', "137": '"Primal Beast"', "138": '"Muerta"', "145": '"Kez"' }, broadcast: { WIN_NEGATIVE: `"Won the match by sheer luck", "Won the match by a stroke of bad luck", "Coasted to victory", "Didn't even show up for the team fight, but my teammates won 4v5"`, WIN_POSITIVE: '"Led the team to victory", "Dominated the opponents and secured the win", "Carried the game to victory", "Treated the opponents like pigs and won", "Won again; this game is just so monotonous and dull", "Simply achieved a win in the match"', LOSE_NEGATIVE: '"Got crushed and lost the match", "Lost the match miserably", "Got my head knocked sideways and lost the match with a blown mindset", "Went fishing but got eaten by the fish, lost the match", "Played terribly", "Simply suffered a loss in the match"', LOSE_POSITIVE: `"Lost the match with no way to turn it around", "Gave it my all, but still lost the match", "Though we lost, we still have honor", "Couldn't carry my teammates, lost the match", "Lost again, it hurts; I'd rather it be me losing"`, message: "{name}'s {hero_name} {comment}.\nKDA: {kda}, GPM/XPM: {gpm_xpm}, Last Hits/Denies: {lh_dn}, Damage/Tower Damage: {damage}, Kill/Death Contribution Rate: {kc_dc}" }, logger: { fetch_guilds_failed: "Failed to fetch guild information.", match_tracked: "Tracked the latest unreported match {match.id} from group {#each messageToLogger as item}{item.platform}:{item.guildId} for users [{#each item.players as player}{player.nickName}({player.steamId}){#if player === item.players[item.players.length - 1]}{/if}{#if player !== item.players[item.players.length - 1]} and {/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}, {/if}{/each}.", parse_request_sent: "The parsing request for match {matchId} has been successfully sent to the STRATZ server.", parse_request_failed: "The parsing request for match {matchId} failed to send.", match_parsed: "Match {matchId} has been parsed, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", match_unparsed: "Match {matchId} exceeded the waiting time [{timeout}] and remains unparsed, an image was generated and published to {#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}, {/if}{/each}.", waiting_for_parse: "Match {matchId} is still being parsed, continue waiting.", report_sent: "Posted {title} on {platform}:{guildId}.", rank_sent: "Posted rank change information of {player.nickName} ({player.steamId}) on {platform}:{guildId}.", ejs_error: "Error rendering EJS template: {error}" } } };
582
600
  }
583
601
  });
584
602
 
585
603
  // src/locales/zh-CN.command.yml
586
604
  var require_zh_CN_command = __commonJS({
587
605
  "src/locales/zh-CN.command.yml"(exports2, module2) {
588
- module2.exports = { commands: { dota2tracker: { subscribe: { description: "订阅后还需玩家在本群绑定SteamID", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "取消订阅本群。", messages: { unsubscribe_success: "取消订阅成功。", not_subscribed: "本群尚未订阅,无需取消订阅。" } }, bind: { description: "绑定SteamID,并起一个别名(也可以不起)", usage: "将你的SteamID与你的账号绑定,若本群已订阅将会实时获取你的新比赛数据发布至群中。", examples: '绑定 123456789\n绑定 123456789 张三\n绑定 123456789 "张 三"', messages: { steam_id_invalid: "SteamID无效。", bind_success: "绑定成功,\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", bind_failed: "绑定失败,{0}", reason_without_match: "SteamID无效或无任何场次。", reason_fetch_failed: "网络状况不佳或其他原因无法验证SteamID,请稍后重试。", already_binded: "你已绑定,无需重复绑定。\n以下是你的个人信息:\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", nick_name_too_long: "别名过长,请限制在20个字符以内。(也可以留空)" } }, unbind: { description: "取消绑定你的个人信息", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "修改绑定时设定的别名", examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。" } }, "query-members": { description: "查询本群已绑定的玩家", messages: { no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "查询指定比赛ID的比赛数据,生成图片发布", examples: "查询比赛 1234567890", messages: { empty_input: "请输入比赛ID。", match_id_invalid: "比赛ID无效。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取比赛数据失败。" } }, "query-recent-match": { description: "查询最近的比赛数据,生成图片发布", usage: "查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID", examples: "查询最近比赛\n查询最近比赛 123456789\n查询最近比赛 张三", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【-绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取玩家最近比赛失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-player": { description: "查询玩家的个人信息,可指定英雄", options: { hero: "查询玩家指定英雄使用情况(同查询英雄,可用别名或ID)" }, usage: "查询指定玩家的个人信息,生成图片发布,可指定英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID", examples: "查询玩家 123456789\n查询玩家 张三\n查询玩家 张三 hero 敌法师", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【-绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "查询英雄技能/面板信息", options: { random: "随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } } } } };
606
+ module2.exports = { commands: { dota2tracker: { subscribe: { description: "订阅后还需玩家在本群绑定SteamID", usage: "订阅后还需玩家在本群绑定SteamID,BOT将订阅本群中已绑定玩家的新比赛数据,在STRATZ比赛解析完成后将比赛数据生成为图片战报发布至本群中。", messages: { subscribed: "本群已订阅,无需重复订阅。", subscribe_success: "订阅成功。" } }, unsubscribe: { description: "取消订阅本群。", messages: { unsubscribe_success: "取消订阅成功。", not_subscribed: "本群尚未订阅,无需取消订阅。" } }, bind: { description: "绑定SteamID,并起一个别名(也可以不起)", usage: "将你的SteamID与你的账号绑定,若本群已订阅将会实时获取你的新比赛数据发布至群中。", examples: '绑定 123456789\n绑定 123456789 张三\n绑定 123456789 "张 三"', messages: { steam_id_invalid: "SteamID无效。", bind_success: "绑定成功,\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", bind_failed: "绑定失败,{0}", reason_without_match: "SteamID无效或无任何场次。", reason_fetch_failed: "网络状况不佳或其他原因无法验证SteamID,请稍后重试。", already_binded: "你已绑定,无需重复绑定。\n以下是你的个人信息:\nID:{userId}\n别名:{nickName}\nSteamID:{steamId}", nick_name_too_long: "别名过长,请限制在20个字符以内。(也可以留空)" } }, unbind: { description: "取消绑定你的个人信息", messages: { unbind_success: "取消绑定成功。", not_binded: "尚未绑定,无需取消绑定。" } }, rename: { description: "修改绑定时设定的别名", examples: '改名 李四\n改名 "李 四"', messages: { rename_success: "改名成功,现在你叫{nick_name}了。", empty_input: "请输入你的别名。", not_binded: "请先绑定,绑定时即可设定别名。", nick_name_too_long: "别名过长,请限制在20个字符以内。" } }, "query-members": { description: "查询本群已绑定的玩家", messages: { no_members: "本群尚无绑定玩家。", query_failed: "查询群友失败。" } }, "query-match": { description: "查询指定比赛ID的比赛数据,生成图片发布", options: { parse: "是否等待解析比赛数据" }, examples: "查询比赛 1234567890\n查询比赛 1234567890 -p\n查询比赛 1234567890 --parse", messages: { empty_input: "请输入比赛ID。", match_id_invalid: "比赛ID无效。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取比赛数据失败。", waiting_for_parse: "比赛数据尚未解析,已发送解析请求到服务器,战报将在解析完成或超时后发送。" } }, "query-recent-match": { description: "查询最近的比赛数据,生成图片发布", options: { parse: "是否等待解析比赛数据" }, usage: "查询指定玩家的最近一场比赛的比赛数据,生成图片发布。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID", examples: "查询最近比赛\n查询最近比赛 123456789\n查询最近比赛 张三\n查询最近比赛 123456789 -p\n查询最近比赛 张三 --parse", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_match: "正在搜索对局详情,请稍后……", query_failed: "获取玩家最近比赛失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-player": { description: "查询玩家的个人信息,可指定英雄", options: { hero: "查询玩家指定英雄使用情况(同查询英雄,可用别名或ID)" }, usage: "查询指定玩家的个人信息,生成图片发布,可指定英雄。\n参数可输入该玩家的SteamID或已在本群绑定玩家的别名,无参数时尝试查询调用指令玩家的SteamID", examples: "查询玩家\n查询玩家 123456789\n查询玩家 张三\n查询玩家 张三 --hero 敌法师\n查询玩家 张三 -o 15", messages: { not_binded: "无参数时默认从已绑定SteamID玩家中寻找你的信息,但你似乎并没有绑定。\n请在本群绑定SteamID。(可输入【绑定 -h】获取帮助)\n或在指令后跟上希望查询的SteamID或已绑定玩家的别名。", steam_id_invalid: "SteamID无效并且未在本群找到此玩家。", querying_player: "正在获取玩家数据,请稍后……", query_failed: "获取玩家信息失败。", not_in_group: "指令调用失败。\n当前不属于群聊状态,必须提供指定玩家的SteamID。" } }, "query-hero": { description: "查询英雄技能/面板信息", options: { random: "随机选择英雄" }, usage: "查询英雄的技能说明与各项数据,生成图片发布。\n参数可输入英雄ID、英雄名、英雄常用别名。", examples: "查询英雄 15\n查询英雄 雷泽\n查询英雄 电魂", messages: { not_found: "未找到输入的英雄,请确认后重新输入。", querying_hero: "正在获取英雄数据,请稍后……", query_failed: "获取英雄数据失败。", empty_input: "请输入参数。" } } } } };
589
607
  }
590
608
  });
591
609
 
592
610
  // src/locales/zh-CN.template.yml
593
611
  var require_zh_CN_template = __commonJS({
594
612
  "src/locales/zh-CN.template.yml"(exports2, module2) {
595
- module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)" } } };
613
+ module2.exports = { dota2tracker: { template: { radiant: "天辉", dire: "夜魇", won: "获胜", lost: "失败", match_id_: "比赛编号:{0}", game_mode_: "模式:{0}", start_time_: "起始时间:{0}", end_time_: "结束时间:{0}", pick_order: "第{0}手", random: "随机", hero_damage_: "英雄伤害:{0}", building_damage_: "建筑伤害:{0}", damage_received_: "受到伤害:{0}", lasthit_: "补刀:{0}", deny_: "反补:{0}", "lh/dn_": "补刀:{0}/{1}", GPM: "GPM", XPM: "XPM", heal_: "治疗量:{0}", crowd_control_duration_: "控制时间:{0}", "GPM/XPM_": "GPM/XPM:{0}", lane: "对线", lane_: "对线:", lane_advantage: "对线优势", lane_disadvantage: "对线劣势", lane_stomp: "对线碾压", lane_stomped: "对线被碾", lane_tie: "对线平手", lane_jungle: "野区霸主", analysis_successful: "录像分析成功", analysis_incomplete: "分析结果不完整", kill: "击杀", kill_contribution_: "参战率:{0}", position: "位置", position_: "位置:", position_1: "优势路", position_2: "中路", position_3: "烈士路", position_4: "采灵芝", position_5: "工具人", position_undefined: "?", total_damage: "总伤害", total_gold: "总经济", total_experience: "总经验", radiant_won: "天辉获胜", dire_won: "夜魇获胜", duration_: "持续时间:{0}", region_: "地区:{0}", match_count_: "场次:", last25matches_: "最近25场:", winrate_: "胜率:", imp_: "表现:", lane_advantage_rate_: "线优率:", top10_: "全期场次前十的英雄:", hero: "英雄", all_matches_: "全期场次:", match_count: "场次", winrate: "胜率", imp: "表现", win_count: "胜场", lose_count: "败场", recently_heroes: "近期使用场次大于1的英雄:", recently_positions: "近25场各个位置的表现:", winning_streak: "连胜", losing_streak: "连败", id: "ID", mode: "模式", kda_kc: "KDA(参战率)", time: "时间", duration: "时长", rank: "段位", un_parsed: "(未解析)", combined_win_loss_summary: "组合胜负情况:", yesterdays_summary: "昨日总结", last_weeks_summary: "上周总结", report_won: "胜", report_lost: "负", report_winrate: "胜率" } } };
596
614
  }
597
615
  });
598
616
 
599
617
  // src/locales/zh-CN.yml
600
618
  var require_zh_CN = __commonJS({
601
619
  "src/locales/zh-CN.yml"(exports2, module2) {
602
- module2.exports = { dota2tracker: { heroes_nicknames: { "0": '请严格遵循 "", "" 格式填写(如下方默认数据,注意是英文半角符号),如果格式有误将仅使用英雄默认名称。可以不包含英雄默认名称。', "1": '"敌法师", "敌法", "AM"', "2": '"斧王"', "3": '"祸乱之源", "祸乱", "水桶腰"', "4": '"血魔"', "5": '"水晶室女", "冰女", "CM"', "6": '"卓尔游侠", "小黑"', "7": '"撼地者", "小牛", "牛头"', "8": '"主宰", "剑圣", "jugg", "奶棒人"', "9": '"米拉娜", "白虎", "pom"', "10": '"变体精灵", "水人"', "11": '"影魔", "影魔王", "SF", "影儿魔儿"', "12": '"幻影长矛手", "PL"', "13": '"帕克"', "14": '"帕吉", "屠夫", "扒鸡", "啪唧"', "15": '"雷泽", "电魂", "电棍"', "16": '"沙王", "SK"', "17": '"风暴之灵", "蓝猫"', "18": '"斯温", "流浪剑客", "流浪"', "19": '"小小"', "20": '"复仇之魂", "复仇", "VS"', "21": '"风行者", "风行", "WR"', "22": '"宙斯"', "23": '"昆卡", "船长"', "25": '"莉娜", "火女"', "26": '"莱恩", "恶魔巫师", "Lion"', "27": '"暗影萨满", "小Y", "小歪"', "28": '"斯拉达", "大鱼", "大鱼人"', "29": '"潮汐猎人", "潮汐", "西瓜皮"', "30": '"巫医"', "31": '"巫妖"', "32": '"力丸", "隐形刺客", "隐刺"', "33": '"谜团"', "34": '"修补匠", "TK", "Tinker"', "35": '"狙击手", "矮人火枪手", "火枪", "传说哥"', "36": '"瘟疫法师", "死灵法", "NEC"', "37": '"术士", "Warlock"', "38": '"兽王"', "39": '"痛苦女王", "女王", "QOP"', "40": '"剧毒术士", "剧毒"', "41": '"虚空假面", "虚空", "JB脸"', "42": '"冥魂大帝", "骷髅王"', "43": '"死亡先知", "DP"', "44": '"幻影刺客", "幻刺", "PA"', "45": '"帕格纳", "骨法", "湮灭法师"', "46": '"圣堂刺客", "圣堂", "TA"', "47": '"冥界亚龙", "毒龙", "Viper"', "48": '"露娜", "月骑", "Luna"', "49": '"龙骑士", "龙骑"', "50": '"戴泽", "暗影牧师", "暗牧"', "51": '"发条技师", "发条"', "52": '"拉席克", "老鹿"', "53": '"先知"', "54": '"噬魂鬼", "小狗"', "55": '"黑暗贤者", "黑贤"', "56": '"克林克兹", "小骷髅"', "57": '"全能骑士", "全能"', "58": '"魅惑魔女", "小鹿"', "59": '"哈斯卡", "神灵", "神灵武士"', "60": '"暗夜魔王", "夜魔"', "61": '"育母蜘蛛", "蜘蛛"', "62": '"赏金猎人", "赏金"', "63": '"编织者", "蚂蚁"', "64": '"杰奇洛", "双头龙"', "65": '"蝙蝠骑士", "蝙蝠"', "66": '"陈", "老陈"', "67": '"幽鬼", "SPE", "UG"', "68": '"远古冰魄", "冰魂"', "69": '"末日使者", "末日", "Doom"', "70": '"熊战士", "拍拍", "拍拍熊"', "71": '"裂魂人", "白牛", "sb"', "72": '"矮人直升机", "飞机"', "73": '"炼金术士", "炼金"', "74": '"祈求者", "卡尔"', "75": '"沉默术士", "沉默"', "76": '"殁境神蚀者", "黑鸟"', "77": '"狼人"', "78": '"酒仙", "熊猫", "熊猫酒仙"', "79": '"暗影恶魔", "毒狗"', "80": '"德鲁伊", "熊德"', "81": '"混沌骑士", "混沌", "CK"', "82": '"米波"', "83": '"树精卫士", "大树", "树精"', "84": '"食人魔魔法师", "蓝胖"', "85": '"不朽尸王", "尸王"', "86": '"拉比克"', "87": '"干扰者", "萨尔"', "88": '"司夜刺客", "小强"', "89": '"娜迦海妖", "小娜迦"', "90": '"光之守卫", "光法"', "91": '"艾欧", "小精灵", "精灵", "IO"', "92": '"维萨吉", "死灵龙", "死灵飞龙"', "93": '"斯拉克", "小鱼", "小鱼人"', "94": '"美杜莎", "一姐", "美杜莎"', "95": '"巨魔战将", "巨魔", "巨馍蘸酱"', "96": '"半人马战行者", "人马", "半人马"', "97": '"马格纳斯", "猛犸"', "98": '"伐木机", "花母鸡"', "99": '"钢背兽", "钢背"', "100": '"巨牙海民", "海民"', "101": '"天怒法师", "天怒"', "102": '"亚巴顿"', "103": '"上古巨神", "大牛"', "104": '"军团指挥官", "军团"', "105": '"工程师", "炸弹", "炸弹人"', "106": '"灰烬之灵", "火猫"', "107": '"大地之灵", "土猫"', "108": '"孽主", "大屁股"', "109": '"恐怖利刃", "TB"', "110": '"凤凰", "烧鸡"', "111": '"神谕者", "神谕"', "112": '"寒冬飞龙", "冰龙"', "113": '"天穹守望者", "电狗"', "114": '"齐天大圣", "大圣"', "119": '"邪影芳灵", "小仙女", "花仙子"', "120": '"石鳞剑士", "滚滚"', "121": '"天涯墨客", "墨客"', "123": '"森海飞霞", "松鼠", "小松鼠", "小松许"', "126": '"虚无之灵", "紫猫"', "128": '"电炎绝手", "老奶奶"', "129": '"玛尔斯"', "131": '"百戏大王"', "135": '"破晓辰星", "大锤"', "136": '"玛西"', "137": '"獸", "畜"', "138": '"琼英碧灵", "奶绿", "绿奶奶"', "145": '"凯", "鸟人"' }, broadcast: { WIN_NEGATIVE: '"侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺赢了比赛", "打团都没来, 队友4V5赢得了比赛"', WIN_POSITIVE: '"带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"', LOSE_NEGATIVE: '"被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"', LOSE_POSITIVE: '"无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"', message: "{name}的{hero_name}{comment}。\nKDA:{kda},GPM/XPM:{gpm_xpm},补刀/反补:{lh_dn},伤害/塔伤:{damage},参战/参葬率:{kc_dc}" } } };
620
+ module2.exports = { dota2tracker: { heroes_nicknames: { "0": '请严格遵循 "", "" 格式填写(如下方默认数据,注意是英文半角符号),如果格式有误将仅使用英雄默认名称。可以不包含英雄默认名称。', "1": '"敌法师", "敌法", "AM"', "2": '"斧王"', "3": '"祸乱之源", "祸乱", "水桶腰"', "4": '"血魔"', "5": '"水晶室女", "冰女", "CM"', "6": '"卓尔游侠", "小黑"', "7": '"撼地者", "小牛", "牛头"', "8": '"主宰", "剑圣", "jugg", "奶棒人"', "9": '"米拉娜", "白虎", "pom"', "10": '"变体精灵", "水人"', "11": '"影魔", "影魔王", "SF", "影儿魔儿"', "12": '"幻影长矛手", "PL"', "13": '"帕克"', "14": '"帕吉", "屠夫", "扒鸡", "啪唧"', "15": '"雷泽", "电魂", "电棍"', "16": '"沙王", "SK"', "17": '"风暴之灵", "蓝猫"', "18": '"斯温", "流浪剑客", "流浪"', "19": '"小小"', "20": '"复仇之魂", "复仇", "VS"', "21": '"风行者", "风行", "WR"', "22": '"宙斯"', "23": '"昆卡", "船长"', "25": '"莉娜", "火女"', "26": '"莱恩", "恶魔巫师", "Lion"', "27": '"暗影萨满", "小Y", "小歪"', "28": '"斯拉达", "大鱼", "大鱼人"', "29": '"潮汐猎人", "潮汐", "西瓜皮"', "30": '"巫医"', "31": '"巫妖"', "32": '"力丸", "隐形刺客", "隐刺"', "33": '"谜团"', "34": '"修补匠", "TK", "Tinker"', "35": '"狙击手", "矮人火枪手", "火枪", "传说哥"', "36": '"瘟疫法师", "死灵法", "NEC"', "37": '"术士", "Warlock"', "38": '"兽王"', "39": '"痛苦女王", "女王", "QOP"', "40": '"剧毒术士", "剧毒"', "41": '"虚空假面", "虚空", "JB脸"', "42": '"冥魂大帝", "骷髅王"', "43": '"死亡先知", "DP"', "44": '"幻影刺客", "幻刺", "PA"', "45": '"帕格纳", "骨法", "湮灭法师"', "46": '"圣堂刺客", "圣堂", "TA"', "47": '"冥界亚龙", "毒龙", "Viper"', "48": '"露娜", "月骑", "Luna"', "49": '"龙骑士", "龙骑"', "50": '"戴泽", "暗影牧师", "暗牧"', "51": '"发条技师", "发条"', "52": '"拉席克", "老鹿"', "53": '"先知"', "54": '"噬魂鬼", "小狗"', "55": '"黑暗贤者", "黑贤"', "56": '"克林克兹", "小骷髅"', "57": '"全能骑士", "全能"', "58": '"魅惑魔女", "小鹿"', "59": '"哈斯卡", "神灵", "神灵武士"', "60": '"暗夜魔王", "夜魔"', "61": '"育母蜘蛛", "蜘蛛"', "62": '"赏金猎人", "赏金"', "63": '"编织者", "蚂蚁"', "64": '"杰奇洛", "双头龙"', "65": '"蝙蝠骑士", "蝙蝠"', "66": '"陈", "老陈"', "67": '"幽鬼", "SPE", "UG"', "68": '"远古冰魄", "冰魂"', "69": '"末日使者", "末日", "Doom"', "70": '"熊战士", "拍拍", "拍拍熊"', "71": '"裂魂人", "白牛", "sb"', "72": '"矮人直升机", "飞机"', "73": '"炼金术士", "炼金"', "74": '"祈求者", "卡尔"', "75": '"沉默术士", "沉默"', "76": '"殁境神蚀者", "黑鸟"', "77": '"狼人"', "78": '"酒仙", "熊猫", "熊猫酒仙"', "79": '"暗影恶魔", "毒狗"', "80": '"德鲁伊", "熊德"', "81": '"混沌骑士", "混沌", "CK"', "82": '"米波"', "83": '"树精卫士", "大树", "树精"', "84": '"食人魔魔法师", "蓝胖"', "85": '"不朽尸王", "尸王"', "86": '"拉比克"', "87": '"干扰者", "萨尔"', "88": '"司夜刺客", "小强"', "89": '"娜迦海妖", "小娜迦"', "90": '"光之守卫", "光法"', "91": '"艾欧", "小精灵", "精灵", "IO"', "92": '"维萨吉", "死灵龙", "死灵飞龙"', "93": '"斯拉克", "小鱼", "小鱼人"', "94": '"美杜莎", "一姐", "美杜莎"', "95": '"巨魔战将", "巨魔", "巨馍蘸酱"', "96": '"半人马战行者", "人马", "半人马"', "97": '"马格纳斯", "猛犸"', "98": '"伐木机", "花母鸡"', "99": '"钢背兽", "钢背"', "100": '"巨牙海民", "海民"', "101": '"天怒法师", "天怒"', "102": '"亚巴顿"', "103": '"上古巨神", "大牛"', "104": '"军团指挥官", "军团"', "105": '"工程师", "炸弹", "炸弹人"', "106": '"灰烬之灵", "火猫"', "107": '"大地之灵", "土猫"', "108": '"孽主", "大屁股"', "109": '"恐怖利刃", "TB"', "110": '"凤凰", "烧鸡"', "111": '"神谕者", "神谕"', "112": '"寒冬飞龙", "冰龙"', "113": '"天穹守望者", "电狗"', "114": '"齐天大圣", "大圣"', "119": '"邪影芳灵", "小仙女", "花仙子"', "120": '"石鳞剑士", "滚滚"', "121": '"天涯墨客", "墨客"', "123": '"森海飞霞", "松鼠", "小松鼠", "小松许"', "126": '"虚无之灵", "紫猫"', "128": '"电炎绝手", "老奶奶"', "129": '"玛尔斯"', "131": '"百戏大王"', "135": '"破晓辰星", "大锤"', "136": '"玛西"', "137": '"獸", "畜"', "138": '"琼英碧灵", "奶绿", "绿奶奶"', "145": '"凯", "鸟人"' }, broadcast: { WIN_NEGATIVE: '"侥幸赢得了比赛", "走狗屎运赢得了比赛", "躺赢了比赛", "打团都没来, 队友4V5赢得了比赛"', WIN_POSITIVE: '"带领团队走向了胜利", "暴打对面后赢得了胜利", " CARRY全场赢得了胜利", "把对面当猪宰了, 赢得了胜利", "又赢了, 这游戏就是这么枯燥, 且乏味", "直接进行一个比赛的赢"', LOSE_NEGATIVE: '"被人按在地上摩擦, 输掉了这场比赛", "悲惨地输掉了比赛", "头都被打歪了, 心态爆炸地输掉了比赛", "捕鱼被鱼吃了, 输掉了比赛", "打的是个几把", "直接进行一个比赛的输"', LOSE_POSITIVE: '"无力回天输掉了比赛", "尽力了, 但还是输了比赛", "背靠世界树, 虽败犹荣", "带不动队友, 输了比赛", "又输了, 很难受, 宁愿输的是我"', message: "{name}的{hero_name}{comment}。\nKDA:{kda},GPM/XPM:{gpm_xpm},补刀/反补:{lh_dn},伤害/塔伤:{damage},参战/参葬率:{kc_dc}" }, logger: { fetch_guilds_failed: "获取群组信息失败。", match_tracked: "追踪到来自{#each messageToLogger as item}群组 {item.platform}:{item.guildId} 的用户[{#each item.players as player}{player.nickName}({player.steamId}){#if player === item.players[item.players.length - 1]}{/if}{#if player !== item.players[item.players.length - 1]}、{/if}{/each}]{#if item !== messageToLogger[messageToLogger.length - 1]}、{/if}{/each}的尚未播报过的最新比赛 {match.id}。", parse_request_sent: "比赛 {matchId} 解析请求已成功发送至STRATZ服务器。", parse_request_failed: "比赛 {matchId} 解析请求发送失败。", match_parsed: "比赛 {matchId} 已解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", match_unparsed: "比赛 {matchId} 超过等待时间[{timeout}]仍未解析,生成图片并发布于{#each guilds as guild}{guild.platform}:{guild.guildId}{#if guild !== guilds[guilds.length - 1]}、{/if}{/each}。", waiting_for_parse: "比赛 {matchId} 尚未解析完成,继续等待。", report_sent: "发布{title}于{platform}:{guildId}。", rank_sent: "向{platform}:{guildId}发布{player.nickName}(${player.steamId})的段位变动信息。", ejs_error: "EJS模板渲染错误:{error}" } } };
603
621
  }
604
622
  });
605
623
 
@@ -607,6 +625,7 @@ var require_zh_CN = __commonJS({
607
625
  var src_exports = {};
608
626
  __export(src_exports, {
609
627
  Config: () => Config,
628
+ GraphqlLanguageEnum: () => GraphqlLanguageEnum,
610
629
  apply: () => apply,
611
630
  inject: () => inject,
612
631
  name: () => name,
@@ -624,7 +643,9 @@ __export(utils_exports, {
624
643
  ImageType: () => ImageType,
625
644
  formatHeroDesc: () => formatHeroDesc,
626
645
  formatNumber: () => formatNumber,
646
+ getFormattedHeroData: () => getFormattedHeroData,
627
647
  getFormattedMatchData: () => getFormattedMatchData,
648
+ getFormattedPlayerData: () => getFormattedPlayerData,
628
649
  getImageUrl: () => getImageUrl,
629
650
  init: () => init,
630
651
  playerisValid: () => playerisValid,
@@ -696,12 +717,12 @@ async function queryHeroFromValve(heroId, languageTag = "zh-CN") {
696
717
  return (await http.get(`https://www.dota2.com/datafeed/herodata?language=${language[languageTag]}&hero_id=${heroId}`)).result.data.heroes[0];
697
718
  }
698
719
  __name(queryHeroFromValve, "queryHeroFromValve");
699
- var HeroDescType = /* @__PURE__ */ ((HeroDescType2) => {
700
- HeroDescType2["Normal"] = "normal";
701
- HeroDescType2["Facet"] = "facet";
702
- HeroDescType2["Scepter"] = "scepter";
703
- HeroDescType2["Shard"] = "shard";
704
- return HeroDescType2;
720
+ var HeroDescType = /* @__PURE__ */ ((HeroDescType3) => {
721
+ HeroDescType3["Normal"] = "normal";
722
+ HeroDescType3["Facet"] = "facet";
723
+ HeroDescType3["Scepter"] = "scepter";
724
+ HeroDescType3["Shard"] = "shard";
725
+ return HeroDescType3;
705
726
  })(HeroDescType || {});
706
727
  var ImageType = /* @__PURE__ */ ((ImageType2) => {
707
728
  ImageType2["Icons"] = "icons";
@@ -1013,6 +1034,140 @@ function getFormattedMatchData(matchQuery, constantsQuery) {
1013
1034
  return match;
1014
1035
  }
1015
1036
  __name(getFormattedMatchData, "getFormattedMatchData");
1037
+ function getFormattedPlayerData(playerQuery, playerExtraQuery, genHero) {
1038
+ const player = playerQuery.player;
1039
+ const playerExtra = playerExtraQuery.player;
1040
+ let filteredDotaPlus = {};
1041
+ playerExtra.dotaPlus.forEach((item) => {
1042
+ if (!filteredDotaPlus[item.heroId] || filteredDotaPlus[item.heroId].level < item.level) {
1043
+ filteredDotaPlus[item.heroId] = {
1044
+ heroId: item.heroId,
1045
+ level: item.level
1046
+ };
1047
+ }
1048
+ });
1049
+ playerExtra.heroesPerformance.forEach((hero) => {
1050
+ if (filteredDotaPlus[hero.hero.id]) {
1051
+ filteredDotaPlus[hero.hero.id].shortName = hero.hero.shortName;
1052
+ filteredDotaPlus[hero.hero.id].winCount = hero.winCount;
1053
+ filteredDotaPlus[hero.hero.id].matchCount = hero.matchCount;
1054
+ }
1055
+ });
1056
+ player.rank = {
1057
+ medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
1058
+ star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
1059
+ leaderboard: player.steamAccount.seasonLeaderboardRank,
1060
+ inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
1061
+ };
1062
+ player.dotaPlus = Object.values(filteredDotaPlus);
1063
+ player.dotaPlus.sort((a, b) => {
1064
+ if (b.level !== a.level) {
1065
+ return b.level - a.level;
1066
+ }
1067
+ return a.heroId - b.heroId;
1068
+ });
1069
+ player.heroesPerformanceTop10 = playerExtra.heroesPerformance.slice(0, 10);
1070
+ if (genHero) {
1071
+ const { matchCount, winCount, imp } = player.heroesPerformanceTop10[0];
1072
+ player.matchCount = matchCount;
1073
+ player.winCount = winCount;
1074
+ player.performance.imp = imp;
1075
+ player.dotaPlus = player.dotaPlus.filter((dpHero) => dpHero.heroId == genHero.heroId);
1076
+ player.genHero = genHero;
1077
+ }
1078
+ return player;
1079
+ }
1080
+ __name(getFormattedPlayerData, "getFormattedPlayerData");
1081
+ function getFormattedHeroData(rawHero) {
1082
+ let hero = Object.assign({}, rawHero);
1083
+ hero.facet_abilities.forEach((fa, i) => {
1084
+ if (fa.abilities.length) {
1085
+ fa.abilities.forEach((ab) => {
1086
+ if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1087
+ if (hero.facets[i].description_loc !== ab.desc_loc)
1088
+ hero.facets[i].abilities.push({
1089
+ id: ab.id,
1090
+ name: ab.name,
1091
+ name_loc: ab.name_loc,
1092
+ description_ability_loc: formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */)
1093
+ });
1094
+ else hero.facets[i].description_loc = formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
1095
+ ab.ability_is_facet = true;
1096
+ ab.facet = hero.facets[i];
1097
+ hero.abilities.push(ab);
1098
+ });
1099
+ }
1100
+ });
1101
+ const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
1102
+ hero.abilities.forEach((ab) => {
1103
+ ab.facets_loc.forEach((facet, i) => {
1104
+ i = i + (hero.facets.length - ab.facets_loc.length);
1105
+ if (i < 0) return;
1106
+ if (facet) {
1107
+ if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1108
+ hero.facets[i].abilities.push({
1109
+ id: ab.id,
1110
+ name: ab.name,
1111
+ name_loc: ab.name_loc,
1112
+ description_ability_loc: formatHeroDesc(facet, ab.special_values, "facet" /* Facet */),
1113
+ attributes: []
1114
+ });
1115
+ }
1116
+ });
1117
+ hero.facets.forEach((facet) => {
1118
+ const svs = ab.special_values.filter((sv) => sv.facet_bonus.name === facet.name);
1119
+ svs.forEach((sv) => {
1120
+ if (sv.heading_loc) {
1121
+ if (!facet.abilities) facet.abilities = [];
1122
+ facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({
1123
+ heading_loc: sv.heading_loc,
1124
+ values: [...sv.facet_bonus.values],
1125
+ is_percentage: sv.is_percentage
1126
+ });
1127
+ }
1128
+ });
1129
+ facet.description_loc = formatHeroDesc(facet.description_loc, svs, "facet" /* Facet */);
1130
+ });
1131
+ ab.desc_loc = formatHeroDesc(ab.desc_loc, ab.special_values, ab.ability_is_facet ? "facet" /* Facet */ : void 0);
1132
+ ab.notes_loc = ab.notes_loc.map((note) => formatHeroDesc(note, ab.special_values));
1133
+ if (ab.ability_has_scepter) ab.scepter_loc = formatHeroDesc(ab.scepter_loc, ab.special_values, "scepter" /* Scepter */);
1134
+ if (ab.ability_has_shard) ab.shard_loc = formatHeroDesc(ab.shard_loc, ab.special_values, "shard" /* Shard */);
1135
+ });
1136
+ hero.talents.forEach((talent) => {
1137
+ const regex = /\{s:(.*?)\}/g;
1138
+ let match;
1139
+ while ((match = regex.exec(talent.name_loc)) !== null) {
1140
+ const specialValueName = match[1];
1141
+ const target = talent.special_values?.find((sv) => sv.name === specialValueName);
1142
+ if (target) {
1143
+ talent.name_loc = talent.name_loc.replace(match[0], target.values_float.join("/"));
1144
+ } else {
1145
+ const abilities = hero.abilities.filter((ability) => ability.special_values.some((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name)));
1146
+ for (const ability of abilities) {
1147
+ const specialValues = ability.special_values.filter((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name));
1148
+ const regex2 = /{s:bonus_(.*?)}/g;
1149
+ let match2;
1150
+ const replacements = [];
1151
+ while ((match2 = regex2.exec(talent.name_loc)) !== null) {
1152
+ const specialValue = specialValues.find((sv) => sv.name === String(match2[1]));
1153
+ const replacement = specialValue?.bonuses.find((bonus) => bonus.name === talent.name)?.value;
1154
+ if (replacement !== void 0) {
1155
+ replacements.push({
1156
+ original: match2[0],
1157
+ replacement
1158
+ });
1159
+ }
1160
+ }
1161
+ replacements.forEach(({ original, replacement }) => {
1162
+ talent.name_loc = talent.name_loc.replace(original, replacement);
1163
+ });
1164
+ }
1165
+ }
1166
+ }
1167
+ });
1168
+ return hero;
1169
+ }
1170
+ __name(getFormattedHeroData, "getFormattedHeroData");
1016
1171
  function sec2time(sec) {
1017
1172
  return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
1018
1173
  }
@@ -1111,6 +1266,12 @@ var dotaconstants2 = __toESM(require("dotaconstants"));
1111
1266
  var import_koishi2 = require("koishi");
1112
1267
  var ejs = __toESM(require("ejs"));
1113
1268
 
1269
+ // require("./locales/**/*.schema.yml") in src/index.ts
1270
+ var globRequire_locales_schema_yml = __glob({
1271
+ "./locales/en-US.schema.yml": () => require_en_US_schema(),
1272
+ "./locales/zh-CN.schema.yml": () => require_zh_CN_schema()
1273
+ });
1274
+
1114
1275
  // require("./locales/**/*.constants.json") in src/index.ts
1115
1276
  var globRequire_locales_constants_json = __glob({
1116
1277
  "./locales/en-US.constants.json": () => require_en_US_constants(),
@@ -1120,9 +1281,11 @@ var globRequire_locales_constants_json = __glob({
1120
1281
  // require("./locales/**/*.yml") in src/index.ts
1121
1282
  var globRequire_locales_yml = __glob({
1122
1283
  "./locales/en-US.command.yml": () => require_en_US_command(),
1284
+ "./locales/en-US.schema.yml": () => require_en_US_schema(),
1123
1285
  "./locales/en-US.template.yml": () => require_en_US_template(),
1124
1286
  "./locales/en-US.yml": () => require_en_US(),
1125
1287
  "./locales/zh-CN.command.yml": () => require_zh_CN_command(),
1288
+ "./locales/zh-CN.schema.yml": () => require_zh_CN_schema(),
1126
1289
  "./locales/zh-CN.template.yml": () => require_zh_CN_template(),
1127
1290
  "./locales/zh-CN.yml": () => require_zh_CN()
1128
1291
  });
@@ -1141,66 +1304,57 @@ var globRequire_locales_template_yml = __glob({
1141
1304
 
1142
1305
  // src/index.ts
1143
1306
  var name = "dota2tracker";
1144
- var usage = `
1145
- DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。
1146
- [本地化/dota2tracker](../../locales/dota2tracker)可以自定义英雄别名和位置代称等文本内容
1147
- **更多信息请进入[插件主页](https://sjtdev.github.io/koishi-plugin-dota2tracker/)与[更新日志](https://github.com/sjtdev/koishi-plugin-dota2tracker/blob/master/changelog.md)查看。**`;
1307
+ var usage = "";
1148
1308
  var inject = ["http", "database", "cron", "puppeteer", "cache"];
1149
1309
  var Config = import_koishi.Schema.intersect([
1150
1310
  import_koishi.Schema.object({
1151
- STRATZ_API_TOKEN: import_koishi.Schema.string().required().role("secret").description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取。"),
1152
- dataParsingTimeoutMinutes: import_koishi.Schema.number().default(60).min(0).max(1440).description("等待比赛数据解析的时间(单位:分钟)。如果数据解析时间超过等待时间,将直接生成战报而不再等待解析完成。"),
1153
- urlInMessageType: import_koishi.Schema.array(
1154
- import_koishi.Schema.union([
1155
- import_koishi.Schema.const("match").description("在查询比赛与战报消息中附带stratz比赛页面链接"),
1156
- import_koishi.Schema.const("player").description("在查询玩家信息消息中附带stratz玩家页面链接"),
1157
- import_koishi.Schema.const("hero").description("在查询英雄数据消息中附带刀塔百科对应英雄页面链接")
1158
- ])
1159
- ).role("checkbox").description("在消息中附带链接,<br/>请选择消息类型:")
1160
- }).description("基础设置"),
1311
+ STRATZ_API_TOKEN: import_koishi.Schema.string().required().role("secret"),
1312
+ dataParsingTimeoutMinutes: import_koishi.Schema.number().default(60).min(0).max(1440),
1313
+ urlInMessageType: import_koishi.Schema.array(import_koishi.Schema.union([import_koishi.Schema.const("match"), import_koishi.Schema.const("player"), import_koishi.Schema.const("hero")])).role("checkbox")
1314
+ }).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.base, acc), {})),
1161
1315
  import_koishi.Schema.intersect([
1162
1316
  import_koishi.Schema.object({
1163
- rankBroadSwitch: import_koishi.Schema.boolean().default(false).description("段位变动播报")
1317
+ rankBroadSwitch: import_koishi.Schema.boolean().default(false)
1164
1318
  }),
1165
1319
  import_koishi.Schema.union([
1166
1320
  import_koishi.Schema.object({
1167
1321
  rankBroadSwitch: import_koishi.Schema.const(true).required(),
1168
- rankBroadStar: import_koishi.Schema.boolean().default(true).description("星级变动播报"),
1169
- rankBroadLeader: import_koishi.Schema.boolean().default(true).description("冠绝名次变动播报"),
1170
- rankBroadFun: import_koishi.Schema.boolean().default(false).description("整活播报模板")
1322
+ rankBroadStar: import_koishi.Schema.boolean().default(true),
1323
+ rankBroadLeader: import_koishi.Schema.boolean().default(true),
1324
+ rankBroadFun: import_koishi.Schema.boolean().default(false)
1171
1325
  }),
1172
1326
  import_koishi.Schema.object({})
1173
1327
  ])
1174
- ]),
1328
+ ]).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.rank, acc), {})),
1175
1329
  import_koishi.Schema.intersect([
1176
1330
  import_koishi.Schema.object({
1177
- dailyReportSwitch: import_koishi.Schema.boolean().default(false).description("日报功能")
1178
- }).description("总结设置"),
1331
+ dailyReportSwitch: import_koishi.Schema.boolean().default(false)
1332
+ }),
1179
1333
  import_koishi.Schema.union([
1180
1334
  import_koishi.Schema.object({
1181
1335
  dailyReportSwitch: import_koishi.Schema.const(true).required(),
1182
- dailyReportHours: import_koishi.Schema.number().min(0).max(23).default(6).description("日报时间小时"),
1183
- dailyReportShowCombi: import_koishi.Schema.boolean().default(true).description("日报是否显示组合")
1336
+ dailyReportHours: import_koishi.Schema.number().min(0).max(23).default(6),
1337
+ dailyReportShowCombi: import_koishi.Schema.boolean().default(true)
1184
1338
  }),
1185
1339
  import_koishi.Schema.object({})
1186
1340
  ]),
1187
1341
  import_koishi.Schema.object({
1188
- weeklyReportSwitch: import_koishi.Schema.boolean().default(false).description("周报功能")
1342
+ weeklyReportSwitch: import_koishi.Schema.boolean().default(false)
1189
1343
  }),
1190
1344
  import_koishi.Schema.union([
1191
1345
  import_koishi.Schema.object({
1192
1346
  weeklyReportSwitch: import_koishi.Schema.const(true).required(),
1193
- weeklyReportDayHours: import_koishi.Schema.tuple([import_koishi.Schema.number().min(1).max(7), import_koishi.Schema.number().min(0).max(23)]).default([1, 10]).description("周报发布于周(几)的(几)点"),
1194
- weeklyReportShowCombi: import_koishi.Schema.boolean().default(true).description("周报是否显示组合")
1347
+ weeklyReportDayHours: import_koishi.Schema.tuple([import_koishi.Schema.number().min(1).max(7), import_koishi.Schema.number().min(0).max(23)]).default([1, 10]),
1348
+ weeklyReportShowCombi: import_koishi.Schema.boolean().default(true)
1195
1349
  }),
1196
1350
  import_koishi.Schema.object({})
1197
1351
  ])
1198
- ]),
1352
+ ]).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.report, acc), {})),
1199
1353
  import_koishi.Schema.object({
1200
- template_match: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`)]).default("match_1").description("生成比赛信息图片使用的模板,见 https://github.com/sjtdev/koishi-plugin-dota2tracker/wiki 有模板展示。"),
1201
- template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1").description("生成玩家信息图片使用的模板。(目前仅有一张模板)"),
1202
- template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1").description("生成英雄信息图片使用的模板。(目前仅有一张模板)")
1203
- }).description("模板设置")
1354
+ template_match: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`)]).default("match_1"),
1355
+ template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1"),
1356
+ template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1")
1357
+ }).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.template, acc), {}))
1204
1358
  ]);
1205
1359
  var pendingMatches = [];
1206
1360
  var random = new import_koishi2.Random(() => Math.random());
@@ -1219,10 +1373,13 @@ async function apply(ctx, config) {
1219
1373
  ctx.i18n.define(supportLanguageTag, globRequire_locales_command_yml(`./locales/${supportLanguageTag}.command.yml`));
1220
1374
  ctx.i18n.define(supportLanguageTag, globRequire_locales_template_yml(`./locales/${supportLanguageTag}.template.yml`));
1221
1375
  }
1222
- const getLanguageTag = /* @__PURE__ */ __name(async function(session, channel, channelId) {
1376
+ const getLanguageTag = /* @__PURE__ */ __name(async function(options) {
1377
+ const { session, channel, channelId } = options || {};
1223
1378
  const resolvedChannel = channel ?? (await ctx.database.get("channel", { id: session?.event.channel.id ?? channelId }))?.at(0);
1224
1379
  return ctx.i18n.fallback((resolvedChannel?.locales ?? []).concat(Object.values(ctx.i18n.locales).map((locale) => Object.keys(locale).at(0)))).find((locale) => Object.keys(GraphqlLanguageEnum).some((language) => locale == language));
1225
1380
  }, "getLanguageTag");
1381
+ const GlobalLanguageTag = await getLanguageTag();
1382
+ usage = $t(GlobalLanguageTag, "dota2tracker.usage");
1226
1383
  ctx.command("dota2tracker.subscribe").alias("订阅本群").action(async ({ session }) => {
1227
1384
  if (session.guild) {
1228
1385
  let currentGuild = (await ctx.database.get("dt_subscribed_guilds", {
@@ -1328,7 +1485,7 @@ async function apply(ctx, config) {
1328
1485
  });
1329
1486
  ctx.command("dota2tracker.query-members").alias("查询群友").action(async ({ session }) => {
1330
1487
  if (session.guild) {
1331
- const languageTag = await getLanguageTag(session);
1488
+ const languageTag = await getLanguageTag({ session });
1332
1489
  const subscribedPlayers = await ctx.database.get("dt_subscribed_players", {
1333
1490
  guildId: session.event.channel.id,
1334
1491
  platform: session.platform
@@ -1429,7 +1586,7 @@ async function apply(ctx, config) {
1429
1586
  hero_name: random2.pick(getHeroNicknames(player.hero.id, languageTag)),
1430
1587
  comment,
1431
1588
  kda: `${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${player.kills}/${player.deaths}/${player.assists}]`,
1432
- GPM_XPM: `${player.goldPerMinute}/${player.experiencePerMinute}`,
1589
+ gpm_xpm: `${player.goldPerMinute}/${player.experiencePerMinute}`,
1433
1590
  lh_dn: `${player.numLastHits}/${player.numDenies}`,
1434
1591
  damage: `${player.heroDamage}/${player.towerDamage}`,
1435
1592
  kc_dc: `${(player.killContribution * 100).toFixed(2)}%/${(player.deathContribution * 100).toFixed(2)}%`
@@ -1444,7 +1601,7 @@ async function apply(ctx, config) {
1444
1601
  return await ctx.puppeteer.render(imageHTML);
1445
1602
  }
1446
1603
  __name(generateMatchImage, "generateMatchImage");
1447
- ctx.command("dota2tracker.query-match <match_id>").alias("查询比赛").action(async ({ session }, match_id) => {
1604
+ ctx.command("dota2tracker.query-match <match_id>").alias("查询比赛").option("parse", "-p").action(async ({ session, options }, match_id) => {
1448
1605
  if (!match_id) {
1449
1606
  session.send(session.text(".empty_input"));
1450
1607
  return;
@@ -1453,19 +1610,32 @@ async function apply(ctx, config) {
1453
1610
  session.send(session.text(".match_id_invalid"));
1454
1611
  return;
1455
1612
  }
1456
- await session.send(session.text(".querying_match"));
1613
+ if (!session.argv?.source.startsWith("dota2tracker.query-recent-match")) await session.send(session.text("commands.dota2tracker.query-match.messages.querying_match"));
1457
1614
  try {
1458
- const languageTag = await getLanguageTag(session);
1615
+ const languageTag = await getLanguageTag({ session });
1459
1616
  const matchQuery = await queryMatchData(Number(match_id));
1460
- const match = await formatMatchData(matchQuery, languageTag);
1461
- const image = await generateMatchImage(match, languageTag);
1462
- session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + image);
1617
+ if (matchQuery.match.parsedDateTime && matchQuery.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0 || !options.parse) {
1618
+ const match = await formatMatchData(matchQuery, languageTag);
1619
+ const image = await generateMatchImage(match, languageTag);
1620
+ session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + image);
1621
+ } else {
1622
+ session.send(session.text("commands.dota2tracker.query-match.messages.waiting_for_parse"));
1623
+ pendingMatches.push({
1624
+ matchId: matchQuery.match.id,
1625
+ guilds: { [languageTag]: [{ guildId: session.event.channel.id, platform: session.event.platform, players: [] }] },
1626
+ queryTime: /* @__PURE__ */ new Date(),
1627
+ hasMessage: true
1628
+ });
1629
+ query("RequestMatchDataAnalysis", {
1630
+ matchId: matchQuery.match.id
1631
+ }).then((response) => ctx.logger.info($t(GlobalLanguageTag, `dota2tracker.logger.parse_request_${response.stratz.matchRetry ? "sent" : "failed"}`, { matchId: matchQuery.match.id })));
1632
+ }
1463
1633
  } catch (error) {
1464
1634
  session.send(session.text(".query_failed"));
1465
1635
  ctx.logger.error(error);
1466
1636
  }
1467
1637
  });
1468
- ctx.command("dota2tracker.query-recent-match [input_data]").alias("查询最近比赛").action(async ({ session }, input_data) => {
1638
+ ctx.command("dota2tracker.query-recent-match [input_data]").alias("查询最近比赛").option("parse", "-p").action(async ({ session, options }, input_data) => {
1469
1639
  if (session.guild || !session.guild && input_data) {
1470
1640
  let sessionPlayer;
1471
1641
  if (!input_data) {
@@ -1490,7 +1660,7 @@ async function apply(ctx, config) {
1490
1660
  }
1491
1661
  let lastMatchId = 0;
1492
1662
  try {
1493
- session.send(session.text(".querying_match"));
1663
+ await session.send(session.text(".querying_match"));
1494
1664
  lastMatchId = (await query("PlayersLastmatchRankinfo", {
1495
1665
  steamAccountIds: [parseInt(flagBindedPlayer?.steamId ?? input_data)]
1496
1666
  })).players[0].matches[0].id;
@@ -1499,11 +1669,7 @@ async function apply(ctx, config) {
1499
1669
  ctx.logger.error(error);
1500
1670
  return;
1501
1671
  }
1502
- const languageTag = await getLanguageTag(session);
1503
- const matchQuery = await queryMatchData(lastMatchId);
1504
- const match = await formatMatchData(matchQuery, languageTag);
1505
- const image = await generateMatchImage(match, languageTag);
1506
- session.send((ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + image);
1672
+ session.execute(`dota2tracker.query-match ${lastMatchId}${options.parse ? " -p" : ""}`);
1507
1673
  } else {
1508
1674
  session.send(session.text(".not_in_group"));
1509
1675
  }
@@ -1511,7 +1677,7 @@ async function apply(ctx, config) {
1511
1677
  ctx.command("dota2tracker.query-player <input_data>").option("hero", "-o <value:string>").alias("查询玩家").action(async ({ session, options }, input_data) => {
1512
1678
  if (session.guild || !session.guild && input_data) {
1513
1679
  let sessionPlayer;
1514
- const languageTag = await getLanguageTag(session);
1680
+ const languageTag = await getLanguageTag({ session });
1515
1681
  if (!input_data) {
1516
1682
  sessionPlayer = (await ctx.database.get("dt_subscribed_players", {
1517
1683
  guildId: session.event.channel.id,
@@ -1535,58 +1701,18 @@ async function apply(ctx, config) {
1535
1701
  session.send(session.text(".querying_player"));
1536
1702
  let heroId = findingHero(options.hero);
1537
1703
  let steamId = flagBindedPlayer?.steamId ?? input_data;
1538
- let player;
1539
1704
  try {
1540
- player = (await query("PlayerInfoWith25Matches", {
1705
+ const playerQuery = await query("PlayerInfoWith25Matches", {
1541
1706
  steamAccountId: steamId,
1542
1707
  heroIds: heroId
1543
- })).player;
1544
- let playerExtra = (await query("PlayerExtraInfo", {
1708
+ });
1709
+ const playerExtraQuery = await query("PlayerExtraInfo", {
1545
1710
  steamAccountId: steamId,
1546
- matchCount: player.matchCount,
1711
+ matchCount: playerQuery.player.matchCount,
1547
1712
  totalHeroCount: Object.keys(dotaconstants2.heroes).length,
1548
1713
  heroIds: heroId
1549
- })).player;
1550
- let filteredDotaPlus = {};
1551
- playerExtra.dotaPlus.forEach((item) => {
1552
- if (!filteredDotaPlus[item.heroId] || filteredDotaPlus[item.heroId].level < item.level) {
1553
- filteredDotaPlus[item.heroId] = {
1554
- heroId: item.heroId,
1555
- level: item.level
1556
- };
1557
- }
1558
1714
  });
1559
- playerExtra.heroesPerformance.forEach((hero) => {
1560
- if (filteredDotaPlus[hero.hero.id]) {
1561
- filteredDotaPlus[hero.hero.id].shortName = hero.hero.shortName;
1562
- filteredDotaPlus[hero.hero.id].winCount = hero.winCount;
1563
- filteredDotaPlus[hero.hero.id].matchCount = hero.matchCount;
1564
- }
1565
- });
1566
- player.rank = {
1567
- medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
1568
- star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
1569
- leaderboard: player.steamAccount.seasonLeaderboardRank,
1570
- inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
1571
- };
1572
- player.dotaPlus = Object.values(filteredDotaPlus);
1573
- player.dotaPlus.sort((a, b) => {
1574
- if (b.level !== a.level) {
1575
- return b.level - a.level;
1576
- }
1577
- return a.heroId - b.heroId;
1578
- });
1579
- player.heroesPerformanceTop10 = playerExtra.heroesPerformance.slice(0, 10);
1580
- if (heroId) {
1581
- const { matchCount, winCount, imp } = player.heroesPerformanceTop10[0];
1582
- player.matchCount = matchCount;
1583
- player.winCount = winCount;
1584
- player.performance.imp = imp;
1585
- player.dotaPlus = player.dotaPlus.filter((dpHero) => dpHero.heroId == heroId);
1586
- player.genHero = {
1587
- name: constantLocales[languageTag].dota2tracker.template.hero_names[heroId]
1588
- };
1589
- }
1715
+ const player = getFormattedPlayerData(playerQuery, playerExtraQuery, heroId ? { heroId, name: constantLocales[languageTag].dota2tracker.template.hero_names[heroId] } : null);
1590
1716
  session.send(
1591
1717
  (ctx.config.urlInMessageType.some((type) => type == "player") ? "https://stratz.com/players/" + player.steamAccount.id : "") + await ctx.puppeteer.render(await genImageHTML(player, config.template_player, "player" /* Player */, ctx, languageTag))
1592
1718
  );
@@ -1599,7 +1725,7 @@ async function apply(ctx, config) {
1599
1725
  }
1600
1726
  });
1601
1727
  ctx.command("dota2tracker.query-hero <input_data>").option("random", "-r").alias("查询英雄").action(async ({ session, options }, input_data) => {
1602
- const languageTag = await getLanguageTag(session);
1728
+ const languageTag = await getLanguageTag({ session });
1603
1729
  if (options.random) input_data = random.pick(Object.keys(dotaconstants2.heroes));
1604
1730
  if (input_data) {
1605
1731
  let heroId = findingHero(input_data);
@@ -1610,91 +1736,7 @@ async function apply(ctx, config) {
1610
1736
  await session.send(session.text(".querying_hero"));
1611
1737
  try {
1612
1738
  let hero = await queryHeroFromValve(heroId, languageTag);
1613
- hero.facet_abilities.forEach((fa, i) => {
1614
- if (fa.abilities.length) {
1615
- fa.abilities.forEach((ab) => {
1616
- if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1617
- if (hero.facets[i].description_loc !== ab.desc_loc)
1618
- hero.facets[i].abilities.push({
1619
- id: ab.id,
1620
- name: ab.name,
1621
- name_loc: ab.name_loc,
1622
- description_ability_loc: formatHeroDesc(ab.desc_loc, ab.special_values, "facet" /* Facet */)
1623
- });
1624
- else hero.facets[i].description_loc = formatHeroDesc(hero.facets[i].description_loc, ab.special_values, "facet" /* Facet */);
1625
- ab.ability_is_facet = true;
1626
- ab.facet = hero.facets[i];
1627
- hero.abilities.push(ab);
1628
- });
1629
- }
1630
- });
1631
- const all_special_values = [...hero.abilities.flatMap((ab) => ab.special_values), ...hero.facet_abilities.flatMap((fas) => fas.abilities.flatMap((fa) => fa.special_values))];
1632
- hero.abilities.forEach((ab) => {
1633
- ab.facets_loc.forEach((facet, i) => {
1634
- i = i + (hero.facets.length - ab.facets_loc.length);
1635
- if (i < 0) return;
1636
- if (facet) {
1637
- if (!hero.facets[i].abilities) hero.facets[i].abilities = [];
1638
- hero.facets[i].abilities.push({
1639
- id: ab.id,
1640
- name: ab.name,
1641
- name_loc: ab.name_loc,
1642
- description_ability_loc: formatHeroDesc(facet, ab.special_values, "facet" /* Facet */),
1643
- attributes: []
1644
- });
1645
- }
1646
- });
1647
- hero.facets.forEach((facet) => {
1648
- const svs = ab.special_values.filter((sv) => sv.facet_bonus.name === facet.name);
1649
- svs.forEach((sv) => {
1650
- if (sv.heading_loc) {
1651
- if (!facet.abilities) facet.abilities = [];
1652
- facet.abilities.find((ability) => ab.id == ability.id)?.attributes.push({
1653
- heading_loc: sv.heading_loc,
1654
- values: [...sv.facet_bonus.values],
1655
- is_percentage: sv.is_percentage
1656
- });
1657
- }
1658
- });
1659
- facet.description_loc = formatHeroDesc(facet.description_loc, svs, "facet" /* Facet */);
1660
- });
1661
- ab.desc_loc = formatHeroDesc(ab.desc_loc, ab.special_values, ab.ability_is_facet ? "facet" /* Facet */ : void 0);
1662
- ab.notes_loc = ab.notes_loc.map((note) => formatHeroDesc(note, ab.special_values));
1663
- if (ab.ability_has_scepter) ab.scepter_loc = formatHeroDesc(ab.scepter_loc, ab.special_values, "scepter" /* Scepter */);
1664
- if (ab.ability_has_shard) ab.shard_loc = formatHeroDesc(ab.shard_loc, ab.special_values, "shard" /* Shard */);
1665
- });
1666
- hero.talents.forEach((talent) => {
1667
- const regex = /\{s:(.*?)\}/g;
1668
- let match;
1669
- while ((match = regex.exec(talent.name_loc)) !== null) {
1670
- const specialValueName = match[1];
1671
- const target = talent.special_values?.find((sv) => sv.name === specialValueName);
1672
- if (target) {
1673
- talent.name_loc = talent.name_loc.replace(match[0], target.values_float.join("/"));
1674
- } else {
1675
- const abilities = hero.abilities.filter((ability) => ability.special_values.some((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name)));
1676
- for (const ability of abilities) {
1677
- const specialValues = ability.special_values.filter((specialValue) => specialValue.bonuses.some((bonus) => bonus.name === talent.name));
1678
- const regex2 = /{s:bonus_(.*?)}/g;
1679
- let match2;
1680
- const replacements = [];
1681
- while ((match2 = regex2.exec(talent.name_loc)) !== null) {
1682
- const specialValue = specialValues.find((sv) => sv.name === String(match2[1]));
1683
- const replacement = specialValue?.bonuses.find((bonus) => bonus.name === talent.name)?.value;
1684
- if (replacement !== void 0) {
1685
- replacements.push({
1686
- original: match2[0],
1687
- replacement
1688
- });
1689
- }
1690
- }
1691
- replacements.forEach(({ original, replacement }) => {
1692
- talent.name_loc = talent.name_loc.replace(original, replacement);
1693
- });
1694
- }
1695
- }
1696
- }
1697
- });
1739
+ hero = getFormattedHeroData(hero);
1698
1740
  await session.send(
1699
1741
  (ctx.config.urlInMessageType.some((type) => type == "hero") ? `https://wiki.dota2.com.cn/hero/${hero["name"].match(/^npc_dota_hero_(.+)$/)[1]}.html` : "") + await ctx.puppeteer.render(await genImageHTML(hero, config.template_hero, "hero" /* Hero */, ctx, languageTag))
1700
1742
  );
@@ -1763,13 +1805,13 @@ async function apply(ctx, config) {
1763
1805
  if (config.dailyReportSwitch) {
1764
1806
  ctx.cron(`0 ${config.dailyReportHours} * * *`, async function() {
1765
1807
  const oneDayAgo = (0, import_moment.default)().subtract(1, "days").unix();
1766
- await report(oneDayAgo, "昨日总结", config.dailyReportShowCombi);
1808
+ await report(oneDayAgo, "dota2tracker.template.yesterdays_summary", config.dailyReportShowCombi);
1767
1809
  });
1768
1810
  }
1769
1811
  if (config.weeklyReportSwitch) {
1770
1812
  ctx.cron(`0 ${config.weeklyReportDayHours[1]} * * ${config.weeklyReportDayHours[0]}`, async function() {
1771
1813
  const oneWeekAgo = (0, import_moment.default)().subtract(1, "weeks").unix();
1772
- await report(oneWeekAgo, "上周总结", config.weeklyReportShowCombi);
1814
+ await report(oneWeekAgo, "dota2tracker.template.last_weeks_summary", config.weeklyReportShowCombi);
1773
1815
  });
1774
1816
  }
1775
1817
  ctx.cron("* * * * *", async function() {
@@ -1787,51 +1829,54 @@ async function apply(ctx, config) {
1787
1829
  for await (const sendedMatchesId of ctx.cache.keys("dt_sended_match_id")) {
1788
1830
  sendedMatchesIds.push(Number(sendedMatchesId));
1789
1831
  }
1790
- await Promise.all(
1791
- lastMatches.filter((match) => !sendedMatchesIds.includes(match.id)).map(async (match) => {
1792
- const tempGuildsByLanguage = {};
1793
- for (const player of match.players) {
1794
- const subscribedPlayers = subscribedPlayersInGuild.filter((subscribedPlayer) => subscribedPlayer.steamId === player.steamAccount.id);
1795
- await Promise.all(
1796
- subscribedPlayers.map(async (subscribedPlayer) => {
1797
- if (subscribedPlayer) {
1798
- const languageTag = await getLanguageTag(void 0, void 0, subscribedPlayer.guildId);
1799
- if (!tempGuildsByLanguage[languageTag]) {
1800
- tempGuildsByLanguage[languageTag] = [];
1801
- }
1802
- const tempGuild = tempGuildsByLanguage[languageTag].find((guild) => guild.guildId === subscribedPlayer.guildId && guild.platform === subscribedPlayer.platform);
1803
- if (tempGuild) {
1804
- tempGuild.players.push(subscribedPlayer);
1805
- } else {
1806
- tempGuildsByLanguage[languageTag].push({
1807
- guildId: subscribedPlayer.guildId,
1808
- platform: subscribedPlayer.platform,
1809
- players: [subscribedPlayer]
1810
- });
1811
- }
1812
- }
1813
- })
1814
- );
1832
+ for (const match of lastMatches.filter((match2) => !sendedMatchesIds.includes(match2.id))) {
1833
+ const tempGuildsByLanguage = {};
1834
+ for (const player of match.players) {
1835
+ const subscribedPlayers = subscribedPlayersInGuild.filter((subscribedPlayer) => subscribedPlayer.steamId === player.steamAccount.id);
1836
+ for (const subscribedPlayer of subscribedPlayers) {
1837
+ if (subscribedPlayer) {
1838
+ const languageTag = await getLanguageTag({ channelId: subscribedPlayer.guildId });
1839
+ if (!tempGuildsByLanguage[languageTag]) {
1840
+ tempGuildsByLanguage[languageTag] = [];
1841
+ }
1842
+ const tempGuild = tempGuildsByLanguage[languageTag].find((guild) => guild.guildId === subscribedPlayer.guildId && guild.platform === subscribedPlayer.platform);
1843
+ if (tempGuild) {
1844
+ tempGuild.players.push(subscribedPlayer);
1845
+ } else {
1846
+ tempGuildsByLanguage[languageTag].push({
1847
+ guildId: subscribedPlayer.guildId,
1848
+ platform: subscribedPlayer.platform,
1849
+ players: [subscribedPlayer]
1850
+ });
1851
+ }
1852
+ }
1815
1853
  }
1816
- pendingMatches.push({
1817
- matchId: match.id,
1818
- guilds: tempGuildsByLanguage,
1819
- queryTime: /* @__PURE__ */ new Date()
1854
+ }
1855
+ pendingMatches.push({
1856
+ matchId: match.id,
1857
+ guilds: tempGuildsByLanguage,
1858
+ queryTime: /* @__PURE__ */ new Date(),
1859
+ hasMessage: true
1860
+ });
1861
+ const messageToLogger = [];
1862
+ Object.entries(tempGuildsByLanguage).forEach(([languageTag, guilds]) => {
1863
+ guilds.forEach((guild) => {
1864
+ messageToLogger.push({
1865
+ languageTag,
1866
+ platform: guild.platform,
1867
+ guildId: guild.guildId,
1868
+ players: guild.players.map((player) => ({ nickName: player.nickName, steamId: player.steamId }))
1869
+ });
1820
1870
  });
1821
- Object.entries(tempGuildsByLanguage).forEach(([languageTag, guilds]) => {
1822
- ctx.logger.info(
1823
- guilds.map(
1824
- (guild) => `追踪到来自语言 ${languageTag} 群组 ${guild.platform}:${guild.guildId} 的用户 ${guild.players.map((player) => `[${player.nickName ?? ""}(${player.steamId})]`).join("、")} 的尚未播报过的最新比赛 ${match.id}。`
1825
- ).join("")
1826
- );
1871
+ });
1872
+ ctx.logger.info($t(GlobalLanguageTag, "dota2tracker.logger.match_tracked", { messageToLogger, match }));
1873
+ if (!match.parsedDateTime) {
1874
+ const response = await query("RequestMatchDataAnalysis", {
1875
+ matchId: match.id
1827
1876
  });
1828
- if (!match.parsedDateTime) {
1829
- query("RequestMatchDataAnalysis", {
1830
- matchId: match.id
1831
- }).then((response) => ctx.logger.info(`比赛 ${match.id} 的` + (response.stratz.matchRetry ? "解析请求已成功发送至STRATZ服务器。" : "解析请求发送失败。")));
1832
- }
1833
- })
1834
- );
1877
+ ctx.logger.info($t(GlobalLanguageTag, `dota2tracker.logger.parse_request_${response.stratz.matchRetry ? "sent" : "failed"}`, { matchId: match.id }));
1878
+ }
1879
+ }
1835
1880
  const rankMap = players.reduce((map, player) => {
1836
1881
  map[player.steamAccount.id] = {
1837
1882
  rank: player.steamAccount.seasonRank,
@@ -1858,7 +1903,7 @@ async function apply(ctx, config) {
1858
1903
  if (prevRank.medal !== currRank.medal || prevRank.star !== currRank.star && config.rankBroadStar || prevRank.leader !== currRank.leader && config.rankBroadLeader) {
1859
1904
  const guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember?.(subPlayer.guildId, subPlayer.userId);
1860
1905
  const name2 = subPlayer.nickName ?? guildMember?.nick ?? players.find((player) => player.steamAccount.id == subPlayer.steamId)?.steamAccount.name ?? subPlayer.steamId;
1861
- const languageTag = await getLanguageTag(void 0, void 0, subPlayer.guildId);
1906
+ const languageTag = await getLanguageTag({ channelId: subPlayer.guildId });
1862
1907
  if (config.rankBroadFun === true) {
1863
1908
  const img = await ctx.puppeteer.render(
1864
1909
  await genImageHTML(
@@ -1882,7 +1927,7 @@ async function apply(ctx, config) {
1882
1927
  const img = await ctx.puppeteer.render(await genImageHTML(currRank, "rank" + (config.rankBroadFun ? "2" : ""), "rank" /* Rank */, ctx, languageTag));
1883
1928
  await ctx.broadcast([`${subPlayer.platform}:${subPlayer.guildId}`], message + img);
1884
1929
  }
1885
- ctx.logger.info(`向 ${subPlayer.platform}:${subPlayer.guildId} 发布段位变动播报信息。`);
1930
+ ctx.logger.info($t(GlobalLanguageTag, "dota2tracker.logger.rank_sent", { platform: subPlayer.platform, guildId: subPlayer.guildId, player: { nickName: subPlayer.nickName, steamId: subPlayer.steamId } }));
1886
1931
  }
1887
1932
  }
1888
1933
  }
@@ -1894,23 +1939,34 @@ async function apply(ctx, config) {
1894
1939
  const now = (0, import_moment.default)();
1895
1940
  const pendingMatch = pendingMatches[(now.hours() * 60 + now.minutes()) % pendingMatches.length];
1896
1941
  try {
1897
- let matchQuery = await queryMatchData(pendingMatch.matchId);
1898
- if (matchQuery.match.parsedDateTime && matchQuery.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0 || import_moment.default.unix(matchQuery.match.endDateTime).isBefore(now.subtract(config.dataParsingTimeoutMinutes, "minutes"))) {
1942
+ const matchQuery = await queryMatchData(pendingMatch.matchId);
1943
+ const hasParsedData = matchQuery.match.parsedDateTime && matchQuery.match.players.filter((player) => player?.stats?.heroDamageReport?.dealtTotal).length > 0;
1944
+ const isMatchTimeout = import_moment.default.unix(matchQuery.match.endDateTime).isBefore(now.subtract(config.dataParsingTimeoutMinutes, "minutes"));
1945
+ const isQueryTimeout = (0, import_moment.default)(pendingMatch.queryTime).isBefore(now.subtract(config.dataParsingTimeoutMinutes, "minutes"));
1946
+ if (hasParsedData || isMatchTimeout && isQueryTimeout) {
1947
+ const guildsToLogger = [];
1899
1948
  for (const languageTag of Object.keys(pendingMatch.guilds)) {
1900
1949
  let match = await formatMatchData(matchQuery, languageTag);
1901
1950
  const img = await generateMatchImage(match, languageTag);
1902
1951
  for (let commingGuild of pendingMatch.guilds[languageTag]) {
1903
- let broadMatchMessage = await generateMatchMessage(match, languageTag, commingGuild);
1952
+ let broadMatchMessage = pendingMatch.hasMessage ? await generateMatchMessage(match, languageTag, commingGuild) : "";
1904
1953
  await ctx.broadcast(
1905
1954
  [`${commingGuild.platform}:${commingGuild.guildId}`],
1906
1955
  broadMatchMessage + (ctx.config.urlInMessageType.some((type) => type == "match") ? "https://stratz.com/matches/" + match.id : "") + img
1907
1956
  );
1908
- ctx.logger.info(`比赛 ${match.id} ${match.parsedDateTime ? "已解析," : "已结束超过1小时仍未被解析,放弃等待解析直接"}生成图片并发布于${commingGuild.platform}:${commingGuild.guildId}。`);
1957
+ guildsToLogger.push({
1958
+ matchId: match.id,
1959
+ timeout: config.dataParsingTimeoutMinutes,
1960
+ platform: commingGuild.platform,
1961
+ guildId: commingGuild.guildId,
1962
+ languageTag
1963
+ });
1909
1964
  }
1910
1965
  }
1966
+ ctx.logger.info($t(GlobalLanguageTag, `dota2tracker.logger.match_${matchQuery.match.parsedDateTime ? "parsed" : "unparsed"}`, { matchId: matchQuery.match.id, guilds: guildsToLogger }));
1911
1967
  ctx.cache.set("dt_sended_match_id", String(pendingMatch.matchId), void 0, days_30);
1912
1968
  pendingMatches = pendingMatches.filter((item) => item.matchId != pendingMatch.matchId);
1913
- } else ctx.logger.info("比赛 %d 尚未解析完成,继续等待。", matchQuery.match.id);
1969
+ } else ctx.logger.info($t(GlobalLanguageTag, "dota2tracker.logger.waiting_for_parse", { matchId: matchQuery.match.id }));
1914
1970
  } catch (error) {
1915
1971
  ctx.logger.error(error);
1916
1972
  await ctx.cache.delete("dt_previous_query_results", String(pendingMatch.matchId));
@@ -1918,7 +1974,7 @@ async function apply(ctx, config) {
1918
1974
  }
1919
1975
  });
1920
1976
  });
1921
- async function report(timeAgo, title, showCombi) {
1977
+ async function report(timeAgo, titleKey, showCombi) {
1922
1978
  const subscribedGuilds = await ctx.database.get("dt_subscribed_guilds", void 0);
1923
1979
  const subscribedPlayersInGuild = (await ctx.database.get("dt_subscribed_players", void 0)).filter((player) => subscribedGuilds.some((guild) => guild.guildId == player.guildId));
1924
1980
  const players = (await query("PlayersMatchesForDaily", {
@@ -1933,7 +1989,7 @@ async function apply(ctx, config) {
1933
1989
  try {
1934
1990
  guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember(subPlayer.guildId, subPlayer.userId);
1935
1991
  } catch (error) {
1936
- ctx.logger.error("获取群组信息失败。" + error);
1992
+ ctx.logger.error($t(GlobalLanguageTag, "dota2tracker.logger.fetch_guilds_failed") + error);
1937
1993
  }
1938
1994
  subPlayer.name = subPlayer.nickName || (guildMember?.nick ?? players.find((player2) => player2.steamAccount.id == subPlayer.steamId)?.steamAccount.name);
1939
1995
  player.winCount = player.matches.filter((match) => match.didRadiantWin == match.players.find((innerPlayer) => innerPlayer.steamAccount.id == player.steamAccount.id).isRadiant).length;
@@ -1972,12 +2028,13 @@ async function apply(ctx, config) {
1972
2028
  });
1973
2029
  const combinations = Array.from(combinationsMap.values());
1974
2030
  try {
2031
+ const languageTag = await getLanguageTag({ channelId: guild.guildId });
1975
2032
  await ctx.broadcast(
1976
2033
  [`${guild.platform}:${guild.guildId}`],
1977
2034
  await ctx.puppeteer.render(
1978
2035
  await genImageHTML(
1979
2036
  {
1980
- title,
2037
+ title: $t(languageTag, titleKey),
1981
2038
  players: currentsubscribedPlayers.sort((a, b) => {
1982
2039
  if (a.matches.length > b.matches.length) return -1;
1983
2040
  else if (a.matches.length < b.matches.length) return 1;
@@ -1989,11 +2046,11 @@ async function apply(ctx, config) {
1989
2046
  "daily",
1990
2047
  "report" /* Report */,
1991
2048
  ctx,
1992
- await getLanguageTag(void 0, void 0, guild.guildId)
2049
+ await getLanguageTag({ channelId: guild.guildId })
1993
2050
  )
1994
2051
  )
1995
2052
  );
1996
- ctx.logger.info(`发布${title}于${guild.platform}:${guild.guildId}`);
2053
+ ctx.logger.info($t(GlobalLanguageTag, "dota2tracker.logger.report_sent", { title: $t(languageTag, titleKey), guildId: guild.guildId, platform: guild.platform }));
1997
2054
  } catch (error) {
1998
2055
  ctx.logger.error(error);
1999
2056
  }
@@ -2047,9 +2104,9 @@ async function apply(ctx, config) {
2047
2104
  });
2048
2105
  if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", html);
2049
2106
  return html;
2050
- } catch (err) {
2051
- ctx2.logger.error("Error rendering EJS template:", err);
2052
- throw err;
2107
+ } catch (error) {
2108
+ ctx2.logger.error(error);
2109
+ throw error;
2053
2110
  }
2054
2111
  }
2055
2112
  __name(genImageHTML, "genImageHTML");
@@ -2093,6 +2150,7 @@ __name(customConvertArrayOfString, "customConvertArrayOfString");
2093
2150
  // Annotate the CommonJS export names for ESM import in node:
2094
2151
  0 && (module.exports = {
2095
2152
  Config,
2153
+ GraphqlLanguageEnum,
2096
2154
  apply,
2097
2155
  inject,
2098
2156
  name,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局",
4
- "version": "1.3.0-pre.5",
4
+ "version": "1.3.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -27,6 +27,7 @@
27
27
  "dota2"
28
28
  ],
29
29
  "dependencies": {
30
+ "date-fns": "^4.1.0",
30
31
  "dotaconstants": "^9.3.0",
31
32
  "ejs": "^3.1.10",
32
33
  "moment": "^2.30.1"
package/readme.md CHANGED
@@ -1,9 +1,12 @@
1
1
  # [@sjtdev/koishi-plugin-dota2tracker](https://sjtdev.github.io/koishi-plugin-dota2tracker/)
2
2
 
3
+ [新文档](https://sjtdev.github.io/koishi-plugin-dota2tracker/)正在缓慢构建中……
4
+
3
5
  [![npm](https://img.shields.io/npm/v/@sjtdev/koishi-plugin-dota2tracker/latest?style=flat-square)](https://www.npmjs.com/package/@sjtdev/koishi-plugin-dota2tracker)
4
6
  [![npm](https://img.shields.io/npm/v/@sjtdev/koishi-plugin-dota2tracker/next?style=flat-square)](https://www.npmjs.com/package/@sjtdev/koishi-plugin-dota2tracker)
5
7
  [![npm downloads](https://img.shields.io/npm/dm/@sjtdev/koishi-plugin-dota2tracker.svg?style=flat-square)](https://www.npmjs.com/package/@sjtdev/koishi-plugin-dota2tracker)
6
- > [!TIP]两个标签取版本号最高的版为最新版本
8
+ > [!TIP]
9
+ > 两个标签取版本号最高的版为最新版本
7
10
 
8
11
  DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。
9
12
  ### 安装
@@ -144,9 +144,9 @@
144
144
  <img src="<%= player.steamAccount.avatar %>" class="avatar" />
145
145
  <span class="name"><%= player.name %></span>
146
146
  <span class="count">
147
- <span class="win">胜<%= player.winCount %></span>
148
- <span class="lose">负<%= player.loseCount %></span>
149
- <span>胜率<%= Math.round((player.winCount / player.matches.length) * 100) %>%</span>
147
+ <span class="win"><%- $t("dota2tracker.template.report_won") %><%= player.winCount %></span>
148
+ <span class="lose"><%- $t("dota2tracker.template.report_lost") %><%= player.loseCount %></span>
149
+ <span><%- $t("dota2tracker.template.report_winrate") %> <%= Math.round((player.winCount / player.matches.length) * 100) %>%</span>
150
150
  </span>
151
151
  <div class="performance">
152
152
  <% const imp = {sign : "", left : 0, right : 0, absValue : Math.abs(player.avgImp)} %>
@@ -169,16 +169,16 @@
169
169
  <% } %>
170
170
  </div>
171
171
  <div class="combinations"<%= !showCombi ? ` style="display:none;"` : "" %>>
172
- <span style="grid-column: 1/-1">组合胜负情况:</span>
172
+ <span style="grid-column: 1/-1"><%- $t("dota2tracker.template.combined_win_loss_summary") %></span>
173
173
  <% combinations.forEach((combi) => {%>
174
174
  <div class="players">
175
175
  <% combi.players.forEach(player => {%>
176
176
  <img src="<%= player.steamAccount.avatar %>" class="avatar" />
177
177
  <% }); %>
178
178
  </div>
179
- <span class="win">胜<%= combi.winCount %></span>
180
- <span class="lose">负<%= combi.matches.length - combi.winCount %></span>
181
- <span>胜率<%= Math.round((combi.winCount / combi.matches.length) * 100) %>%</span>
179
+ <span class="win"><%- $t("dota2tracker.template.report_won") %><%= combi.winCount %></span>
180
+ <span class="lose"><%- $t("dota2tracker.template.report_lost") %><%= combi.matches.length - combi.winCount %></span>
181
+ <span><%- $t("dota2tracker.template.report_winrate") %> <%= Math.round((combi.winCount / combi.matches.length) * 100) %>%</span>
182
182
  <% }); %>
183
183
  </div>
184
184
  </body>