@sjtdev/koishi-plugin-dota2tracker 1.3.1 → 1.4.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
@@ -38,14 +38,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
38
38
  // src/locales/en-US.schema.yml
39
39
  var require_en_US_schema = __commonJS({
40
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)" } } };
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)", playerRankEstimate: "Estimate the rank of players without a rank in the player template <br>Estimated rank will be displayed as a gray image" } } };
42
42
  }
43
43
  });
44
44
 
45
45
  // src/locales/zh-CN.schema.yml
46
46
  var require_zh_CN_schema = __commonJS({
47
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: "生成英雄信息图片使用的模板。(目前仅有一张模板)" } } };
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: "生成英雄信息图片使用的模板。(目前仅有一张模板)", playerRankEstimate: "在player模板中对没有段位的玩家进行段位估算 <br>估算的段位将以灰色图片显示" } } };
49
49
  }
50
50
  });
51
51
 
@@ -347,7 +347,7 @@ var require_zh_CN_constants = __commonJS({
347
347
  ALL_PICK_RANKED: "全英雄选择",
348
348
  TURBO: "加速模式",
349
349
  MUTATION: "",
350
- UNKNOWN: ""
350
+ UNKNOWN: "未知"
351
351
  },
352
352
  lobby_types: {
353
353
  INVALID: "",
@@ -589,7 +589,7 @@ var require_en_US_command = __commonJS({
589
589
  // src/locales/en-US.template.yml
590
590
  var require_en_US_template = __commonJS({
591
591
  "src/locales/en-US.template.yml"(exports2, module2) {
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" } } };
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", anonymous_player_1: "This profile is private.", anonymous_player_2: "Background is for display purposes only. It is not {player}’s data." } } };
593
593
  }
594
594
  });
595
595
 
@@ -610,7 +610,7 @@ var require_zh_CN_command = __commonJS({
610
610
  // src/locales/zh-CN.template.yml
611
611
  var require_zh_CN_template = __commonJS({
612
612
  "src/locales/zh-CN.template.yml"(exports2, module2) {
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: "胜率" } } };
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: "胜率", anonymous_player_1: "数据未公开。", anonymous_player_2: "背景仅供展示目的,不属于{player}的数据。" } } };
614
614
  }
615
615
  });
616
616
 
@@ -632,7 +632,7 @@ __export(src_exports, {
632
632
  usage: () => usage
633
633
  });
634
634
  module.exports = __toCommonJS(src_exports);
635
- var import_koishi = require("koishi");
635
+ var import_koishi2 = require("koishi");
636
636
 
637
637
  // src/utils.ts
638
638
  var utils_exports = {};
@@ -641,6 +641,7 @@ __export(utils_exports, {
641
641
  HeroDescType: () => HeroDescType,
642
642
  ImageFormat: () => ImageFormat,
643
643
  ImageType: () => ImageType,
644
+ enhancedSimpleHashToSeed: () => enhancedSimpleHashToSeed,
644
645
  formatHeroDesc: () => formatHeroDesc,
645
646
  formatNumber: () => formatNumber,
646
647
  getFormattedHeroData: () => getFormattedHeroData,
@@ -659,6 +660,8 @@ __export(utils_exports, {
659
660
  var import_fs = __toESM(require("fs"));
660
661
  var dotaconstants = __toESM(require("dotaconstants"));
661
662
  var import_path = __toESM(require("path"));
663
+ var import_koishi = require("koishi");
664
+ var pluginDir = import_path.default.join(__dirname, "..");
662
665
  var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
663
666
  var http = null;
664
667
  var setTimeout;
@@ -704,8 +707,7 @@ async function query(queryName, variables) {
704
707
  }
705
708
  __name(query, "query");
706
709
  function loadGraphqlFile(queryName) {
707
- const filepath = `./node_modules/@sjtdev/koishi-plugin-dota2tracker/queries/${queryName}.graphql`;
708
- return import_fs.default.readFileSync(filepath, { encoding: "utf-8" }).replace(/[\r\n]+/g, " ");
710
+ return import_fs.default.readFileSync(import_path.default.join(pluginDir, "queries", `${queryName}.graphql`), { encoding: "utf-8" }).replace(/[\r\n]+/g, " ");
709
711
  }
710
712
  __name(loadGraphqlFile, "loadGraphqlFile");
711
713
  async function queryHeroFromValve(heroId, languageTag = "zh-CN") {
@@ -743,8 +745,8 @@ var ImageFormat = /* @__PURE__ */ ((ImageFormat2) => {
743
745
  function getImageUrl(image, type = "local" /* Local */, format = "png" /* png */) {
744
746
  if (type === "local" /* Local */) {
745
747
  try {
746
- if (format === "svg" /* svg */) return import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.svg`);
747
- const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.${format}`);
748
+ if (format === "svg" /* svg */) return import_fs.default.readFileSync(import_path.default.join(pluginDir, "template", "images", `${image}.svg`));
749
+ const imageData = import_fs.default.readFileSync(import_path.default.join(pluginDir, "template", "images", `${image}.${format}`));
748
750
  const base64Data = imageData.toString("base64");
749
751
  return `data:image/png;base64,${base64Data}`;
750
752
  } catch (error) {
@@ -1034,9 +1036,35 @@ function getFormattedMatchData(matchQuery, constantsQuery) {
1034
1036
  return match;
1035
1037
  }
1036
1038
  __name(getFormattedMatchData, "getFormattedMatchData");
1037
- function getFormattedPlayerData(playerQuery, playerExtraQuery, genHero) {
1039
+ function getFormattedPlayerData(param) {
1040
+ const { playerQuery, playerExtraQuery, genHero, estimateRank } = param;
1038
1041
  const player = playerQuery.player;
1039
1042
  const playerExtra = playerExtraQuery?.player;
1043
+ if (player.steamAccount.isAnonymous) {
1044
+ for (let index = 0; index < 25; index++) {
1045
+ const random2 = new import_koishi.Random(() => enhancedSimpleHashToSeed(`${player.steamAccount.id}-${index}`));
1046
+ player.matches.push({
1047
+ id: 1e9 + index,
1048
+ gameMode: "UNKNOWN",
1049
+ lobbyType: "UNRANKED",
1050
+ didRadiantWin: random2.bool(0.5),
1051
+ rank: random2.int(0, 8) * 10,
1052
+ radiantKills: [random2.int(0, 30)],
1053
+ direKills: [random2.int(0, 30)],
1054
+ parsedDateTime: 1,
1055
+ players: [
1056
+ {
1057
+ steamAccount: { id: player.steamAccount.id },
1058
+ isRadiant: true,
1059
+ kills: random2.int(0, 20),
1060
+ deaths: random2.int(0, 20),
1061
+ assists: random2.int(0, 20),
1062
+ hero: { id: random2.pick(Object.keys(dotaconstants.heroes)), shortName: dotaconstants.heroes[random2.pick(Object.keys(dotaconstants.heroes))].name.match(/^npc_dota_hero_(.+)$/)[1] }
1063
+ }
1064
+ ]
1065
+ });
1066
+ }
1067
+ }
1040
1068
  let filteredDotaPlus = {};
1041
1069
  playerExtra?.dotaPlus?.forEach((item) => {
1042
1070
  if (!filteredDotaPlus[item.heroId] || filteredDotaPlus[item.heroId].level < item.level) {
@@ -1053,6 +1081,44 @@ function getFormattedPlayerData(playerQuery, playerExtraQuery, genHero) {
1053
1081
  filteredDotaPlus[hero.hero.id].matchCount = hero.matchCount;
1054
1082
  }
1055
1083
  });
1084
+ if (!player.steamAccount.seasonRank && estimateRank && !player.steamAccount.isAnonymous) {
1085
+ let estimateWeightedRank = function(player2) {
1086
+ const ranks = player2.matches.map((match) => match.rank);
1087
+ const validRanks = ranks.filter(validateRank);
1088
+ if (validRanks.length === 0) {
1089
+ return "Unknown";
1090
+ }
1091
+ const totalWeight = validRanks.reduce((sum, _, index) => sum + calculateWeight(index, validRanks.length), 0);
1092
+ const weightedAverage = validRanks.reduce((sum, rank, index) => {
1093
+ const value = rankToValue(rank);
1094
+ const weight = calculateWeight(index, validRanks.length);
1095
+ return sum + value * weight;
1096
+ }, 0) / totalWeight;
1097
+ const tier = Math.floor(weightedAverage / 6);
1098
+ const stars = Math.round(weightedAverage % 6);
1099
+ return tier * 10 + stars;
1100
+ function rankToValue(rank) {
1101
+ const tier2 = Math.floor(rank / 10);
1102
+ const stars2 = rank % 10;
1103
+ return tier2 * 6 + stars2;
1104
+ }
1105
+ __name(rankToValue, "rankToValue");
1106
+ function calculateWeight(index, total) {
1107
+ return 1 - 0.5 / (total - 1) * index;
1108
+ }
1109
+ __name(calculateWeight, "calculateWeight");
1110
+ function validateRank(rank) {
1111
+ if (rank === 80) return true;
1112
+ const tier2 = Math.floor(rank / 10);
1113
+ const stars2 = rank % 10;
1114
+ return tier2 >= 1 && tier2 <= 8 && stars2 >= 0 && stars2 <= 5;
1115
+ }
1116
+ __name(validateRank, "validateRank");
1117
+ };
1118
+ __name(estimateWeightedRank, "estimateWeightedRank");
1119
+ player.isEstimatedRank = true;
1120
+ player.steamAccount.seasonRank = estimateWeightedRank(player);
1121
+ }
1056
1122
  player.rank = {
1057
1123
  medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
1058
1124
  star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
@@ -1075,8 +1141,6 @@ function getFormattedPlayerData(playerQuery, playerExtraQuery, genHero) {
1075
1141
  player.dotaPlus = player.dotaPlus.filter((dpHero) => dpHero.heroId == genHero.heroId);
1076
1142
  player.genHero = genHero;
1077
1143
  }
1078
- if (player.steamAccount.isAnonymous) {
1079
- }
1080
1144
  return player;
1081
1145
  }
1082
1146
  __name(getFormattedPlayerData, "getFormattedPlayerData");
@@ -1181,7 +1245,7 @@ __name(formatNumber, "formatNumber");
1181
1245
  function readDirectoryFilesSync(directoryPath) {
1182
1246
  try {
1183
1247
  const files = import_fs.default.readdirSync(directoryPath);
1184
- const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
1248
+ const fileNames = files.filter((file) => import_path.default.extname(file).toLowerCase() === ".ejs").map((file) => import_path.default.basename(file, ".ejs"));
1185
1249
  return fileNames;
1186
1250
  } catch (error) {
1187
1251
  console.error("Error reading directory:", error);
@@ -1259,13 +1323,26 @@ function formatHeroDesc(template, special_values, type = "normal" /* Normal */)
1259
1323
  });
1260
1324
  }
1261
1325
  __name(formatHeroDesc, "formatHeroDesc");
1326
+ function enhancedSimpleHashToSeed(inputString) {
1327
+ const encoded = btoa(inputString);
1328
+ let total = 0;
1329
+ let complexFactor = 1;
1330
+ for (let i = 0; i < encoded.length; i++) {
1331
+ total += encoded.charCodeAt(i) * complexFactor;
1332
+ complexFactor++;
1333
+ total %= 9973;
1334
+ }
1335
+ total = total % 9973 * (total % 9973) % 9973;
1336
+ return total % 1e3 / 1e3;
1337
+ }
1338
+ __name(enhancedSimpleHashToSeed, "enhancedSimpleHashToSeed");
1262
1339
 
1263
1340
  // src/index.ts
1264
1341
  var import_fs2 = __toESM(require("fs"));
1265
1342
  var import_path2 = __toESM(require("path"));
1266
1343
  var import_moment = __toESM(require("moment"));
1267
1344
  var dotaconstants2 = __toESM(require("dotaconstants"));
1268
- var import_koishi2 = require("koishi");
1345
+ var import_koishi3 = require("koishi");
1269
1346
  var ejs = __toESM(require("ejs"));
1270
1347
 
1271
1348
  // require("./locales/**/*.schema.yml") in src/index.ts
@@ -1308,58 +1385,60 @@ var globRequire_locales_template_yml = __glob({
1308
1385
  var name = "dota2tracker";
1309
1386
  var usage = "";
1310
1387
  var inject = ["http", "database", "cron", "puppeteer", "cache"];
1311
- var Config = import_koishi.Schema.intersect([
1312
- import_koishi.Schema.object({
1313
- STRATZ_API_TOKEN: import_koishi.Schema.string().required().role("secret"),
1314
- dataParsingTimeoutMinutes: import_koishi.Schema.number().default(60).min(0).max(1440),
1315
- 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")
1388
+ var pluginDir2 = import_path2.default.resolve(__dirname, "..");
1389
+ var Config = import_koishi2.Schema.intersect([
1390
+ import_koishi2.Schema.object({
1391
+ STRATZ_API_TOKEN: import_koishi2.Schema.string().required().role("secret"),
1392
+ dataParsingTimeoutMinutes: import_koishi2.Schema.number().default(60).min(0).max(1440),
1393
+ urlInMessageType: import_koishi2.Schema.array(import_koishi2.Schema.union([import_koishi2.Schema.const("match"), import_koishi2.Schema.const("player"), import_koishi2.Schema.const("hero")])).role("checkbox")
1316
1394
  }).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.base, acc), {})),
1317
- import_koishi.Schema.intersect([
1318
- import_koishi.Schema.object({
1319
- rankBroadSwitch: import_koishi.Schema.boolean().default(false)
1395
+ import_koishi2.Schema.intersect([
1396
+ import_koishi2.Schema.object({
1397
+ rankBroadSwitch: import_koishi2.Schema.boolean().default(false)
1320
1398
  }),
1321
- import_koishi.Schema.union([
1322
- import_koishi.Schema.object({
1323
- rankBroadSwitch: import_koishi.Schema.const(true).required(),
1324
- rankBroadStar: import_koishi.Schema.boolean().default(true),
1325
- rankBroadLeader: import_koishi.Schema.boolean().default(true),
1326
- rankBroadFun: import_koishi.Schema.boolean().default(false)
1399
+ import_koishi2.Schema.union([
1400
+ import_koishi2.Schema.object({
1401
+ rankBroadSwitch: import_koishi2.Schema.const(true).required(),
1402
+ rankBroadStar: import_koishi2.Schema.boolean().default(true),
1403
+ rankBroadLeader: import_koishi2.Schema.boolean().default(true),
1404
+ rankBroadFun: import_koishi2.Schema.boolean().default(false)
1327
1405
  }),
1328
- import_koishi.Schema.object({})
1406
+ import_koishi2.Schema.object({})
1329
1407
  ])
1330
1408
  ]).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.rank, acc), {})),
1331
- import_koishi.Schema.intersect([
1332
- import_koishi.Schema.object({
1333
- dailyReportSwitch: import_koishi.Schema.boolean().default(false)
1409
+ import_koishi2.Schema.intersect([
1410
+ import_koishi2.Schema.object({
1411
+ dailyReportSwitch: import_koishi2.Schema.boolean().default(false)
1334
1412
  }),
1335
- import_koishi.Schema.union([
1336
- import_koishi.Schema.object({
1337
- dailyReportSwitch: import_koishi.Schema.const(true).required(),
1338
- dailyReportHours: import_koishi.Schema.number().min(0).max(23).default(6),
1339
- dailyReportShowCombi: import_koishi.Schema.boolean().default(true)
1413
+ import_koishi2.Schema.union([
1414
+ import_koishi2.Schema.object({
1415
+ dailyReportSwitch: import_koishi2.Schema.const(true).required(),
1416
+ dailyReportHours: import_koishi2.Schema.number().min(0).max(23).default(6),
1417
+ dailyReportShowCombi: import_koishi2.Schema.boolean().default(true)
1340
1418
  }),
1341
- import_koishi.Schema.object({})
1419
+ import_koishi2.Schema.object({})
1342
1420
  ]),
1343
- import_koishi.Schema.object({
1344
- weeklyReportSwitch: import_koishi.Schema.boolean().default(false)
1421
+ import_koishi2.Schema.object({
1422
+ weeklyReportSwitch: import_koishi2.Schema.boolean().default(false)
1345
1423
  }),
1346
- import_koishi.Schema.union([
1347
- import_koishi.Schema.object({
1348
- weeklyReportSwitch: import_koishi.Schema.const(true).required(),
1349
- weeklyReportDayHours: import_koishi.Schema.tuple([import_koishi.Schema.number().min(1).max(7), import_koishi.Schema.number().min(0).max(23)]).default([1, 10]),
1350
- weeklyReportShowCombi: import_koishi.Schema.boolean().default(true)
1424
+ import_koishi2.Schema.union([
1425
+ import_koishi2.Schema.object({
1426
+ weeklyReportSwitch: import_koishi2.Schema.const(true).required(),
1427
+ weeklyReportDayHours: import_koishi2.Schema.tuple([import_koishi2.Schema.number().min(1).max(7), import_koishi2.Schema.number().min(0).max(23)]).default([1, 10]),
1428
+ weeklyReportShowCombi: import_koishi2.Schema.boolean().default(true)
1351
1429
  }),
1352
- import_koishi.Schema.object({})
1430
+ import_koishi2.Schema.object({})
1353
1431
  ])
1354
1432
  ]).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.report, acc), {})),
1355
- import_koishi.Schema.object({
1356
- template_match: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`)]).default("match_1"),
1357
- template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1"),
1358
- template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1")
1433
+ import_koishi2.Schema.object({
1434
+ template_match: import_koishi2.Schema.union([...readDirectoryFilesSync(import_path2.default.join(pluginDir2, "template", "match"))]).default("match_1"),
1435
+ template_player: import_koishi2.Schema.union([...readDirectoryFilesSync(import_path2.default.join(pluginDir2, "template", "player"))]).default("player_1"),
1436
+ template_hero: import_koishi2.Schema.union([...readDirectoryFilesSync(import_path2.default.join(pluginDir2, "template", "hero"))]).default("hero_1"),
1437
+ playerRankEstimate: import_koishi2.Schema.boolean().default(true)
1359
1438
  }).i18n(["zh-CN", "en-US"].reduce((acc, cur) => (acc[cur] = globRequire_locales_schema_yml(`./locales/${cur}.schema.yml`)._config.template, acc), {}))
1360
1439
  ]);
1361
1440
  var pendingMatches = [];
1362
- var random = new import_koishi2.Random(() => Math.random());
1441
+ var random = new import_koishi3.Random(() => Math.random());
1363
1442
  var days_30 = 2592e6;
1364
1443
  var GraphqlLanguageEnum = /* @__PURE__ */ ((GraphqlLanguageEnum2) => {
1365
1444
  GraphqlLanguageEnum2["en-US"] = "ENGLISH";
@@ -1572,7 +1651,7 @@ async function apply(ctx, config) {
1572
1651
  let idsToFind = guild.players.map((player) => player.steamId);
1573
1652
  let broadPlayers = match.players.filter((item) => idsToFind.includes(item.steamAccountId));
1574
1653
  for (let player of broadPlayers) {
1575
- const random2 = new import_koishi2.Random(() => enhancedSimpleHashToSeed(`${match.id}-${player.steamAccountId}-${player.playerSlot}`));
1654
+ const random2 = new import_koishi3.Random(() => enhancedSimpleHashToSeed(`${match.id}-${player.steamAccountId}-${player.playerSlot}`));
1576
1655
  let comment;
1577
1656
  if (player.isRadiant == match.didRadiantWin) {
1578
1657
  if (player.deathContribution < 0.2 || player.killContribution > 0.75 || player.heroDamage / player.networth > 1.5 || player.towerDamage > 1e4 || player.imp > 0)
@@ -1707,8 +1786,8 @@ async function apply(ctx, config) {
1707
1786
  }
1708
1787
  session.send(session.text(".querying_player"));
1709
1788
  let heroId = findingHero(options.hero);
1710
- let steamId = flagBindedPlayer?.steamId ?? input_data;
1711
1789
  try {
1790
+ let steamId = Number(flagBindedPlayer?.steamId ?? input_data);
1712
1791
  const playerQuery = await query("PlayerInfoWith25Matches", {
1713
1792
  steamAccountId: steamId,
1714
1793
  heroIds: heroId
@@ -1724,7 +1803,12 @@ async function apply(ctx, config) {
1724
1803
  dotaPlus: null
1725
1804
  }
1726
1805
  };
1727
- const player = getFormattedPlayerData(playerQuery, playerExtraQuery, heroId ? { heroId, name: constantLocales[languageTag].dota2tracker.template.hero_names[heroId] } : null);
1806
+ const player = getFormattedPlayerData({
1807
+ playerQuery,
1808
+ playerExtraQuery,
1809
+ genHero: heroId ? { heroId, name: constantLocales[languageTag].dota2tracker.template.hero_names[heroId] } : null,
1810
+ estimateRank: config.playerRankEstimate
1811
+ });
1728
1812
  session.send(
1729
1813
  (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))
1730
1814
  );
@@ -2091,7 +2175,7 @@ async function apply(ctx, config) {
2091
2175
  }
2092
2176
  __name($t, "$t");
2093
2177
  async function genImageHTML(data, template, type, ctx2, languageTag) {
2094
- const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
2178
+ const templatePath = import_path2.default.join(pluginDir2, "template", type, `${template}.ejs`);
2095
2179
  const templateData = {
2096
2180
  data,
2097
2181
  utils: utils_exports,
@@ -2101,7 +2185,8 @@ async function apply(ctx, config) {
2101
2185
  moment: import_moment.default,
2102
2186
  eh: escapeHTML,
2103
2187
  $t: templateI18nHelper,
2104
- languageTag
2188
+ languageTag,
2189
+ Random: import_koishi3.Random
2105
2190
  };
2106
2191
  function templateI18nHelper(key, param) {
2107
2192
  return $t(languageTag, key, param);
@@ -2111,7 +2196,7 @@ async function apply(ctx, config) {
2111
2196
  const html = await ejs.renderFile(templatePath, templateData, {
2112
2197
  strict: false
2113
2198
  });
2114
- if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", html);
2199
+ if (process.env.NODE_ENV === "development") import_fs2.default.writeFileSync(import_path2.default.join(pluginDir2, "temp.html"), html);
2115
2200
  return html;
2116
2201
  } catch (error) {
2117
2202
  ctx2.logger.error(error);
@@ -2121,19 +2206,6 @@ async function apply(ctx, config) {
2121
2206
  __name(genImageHTML, "genImageHTML");
2122
2207
  }
2123
2208
  __name(apply, "apply");
2124
- function enhancedSimpleHashToSeed(inputString) {
2125
- const encoded = btoa(inputString);
2126
- let total = 0;
2127
- let complexFactor = 1;
2128
- for (let i = 0; i < encoded.length; i++) {
2129
- total += encoded.charCodeAt(i) * complexFactor;
2130
- complexFactor++;
2131
- total %= 9973;
2132
- }
2133
- total = total % 9973 * (total % 9973) % 9973;
2134
- return total % 1e3 / 1e3;
2135
- }
2136
- __name(enhancedSimpleHashToSeed, "enhancedSimpleHashToSeed");
2137
2209
  function escapeHTML(str) {
2138
2210
  if (str == null) return "";
2139
2211
  return str.replace(/[&<>"']/g, function(match) {
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.1",
4
+ "version": "1.4.0",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -550,7 +550,7 @@
550
550
  </div>` : ""}
551
551
  <div class="rank">
552
552
  <img
553
- src="${utils.getImageUrl('medal_' +(player.inTop100??player.rank.medal))}"
553
+ src="${utils.getImageUrl('medal_' +(player.rank.inTop100??player.rank.medal))}"
554
554
  class="medal"
555
555
  />
556
556
  <img src="${utils.getImageUrl('star_' + player.rank.star)}" class="stars" />
@@ -0,0 +1,5 @@
1
+ <div class="blur-overlay">
2
+ <span class="lock-icon">🔒</span>
3
+ <span class="lock-text"><%= $t("dota2tracker.template.anonymous_player_1") %></span>
4
+ <span class="lock-sub"><%= $t("dota2tracker.template.anonymous_player_2",{player:player.steamAccount.name}) %></span>
5
+ </div>