@sjtdev/koishi-plugin-dota2tracker 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -44,285 +44,22 @@ var utils_exports = {};
44
44
  __export(utils_exports, {
45
45
  CONFIGS: () => CONFIGS,
46
46
  ImageType: () => ImageType,
47
+ formatNumber: () => formatNumber,
47
48
  getFormattedMatchData: () => getFormattedMatchData,
48
49
  getImageUrl: () => getImageUrl,
49
- query: () => query
50
+ playerisValid: () => playerisValid,
51
+ query: () => query,
52
+ readDirectoryFilesSync: () => readDirectoryFilesSync,
53
+ sec2time: () => sec2time,
54
+ winRateColor: () => winRateColor
50
55
  });
51
56
  var import_axios = __toESM(require("axios"));
52
57
  var import_fs = __toESM(require("fs"));
53
- var dotaconstants = __toESM(require("dotaconstants"));
54
- var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
55
- async function query(query_str) {
56
- return await import_axios.default.post(CONFIGS.STRATZ_API.URL, query_str, {
57
- headers: {
58
- "Content-Type": "application/graphql",
59
- Authorization: `Bearer ${CONFIGS.STRATZ_API.TOKEN}`
60
- }
61
- });
62
- }
63
- __name(query, "query");
64
- var ImageType = /* @__PURE__ */ ((ImageType2) => {
65
- ImageType2["Icons"] = "icons";
66
- ImageType2["Heroes"] = "heroes";
67
- ImageType2["HeroIcons"] = "heroes/icons";
68
- ImageType2["Items"] = "items";
69
- ImageType2["Abilities"] = "abilities";
70
- ImageType2["Local"] = "local";
71
- return ImageType2;
72
- })(ImageType || {});
73
- function getImageUrl(image, type = "local" /* Local */) {
74
- if (type === "local" /* Local */) {
75
- try {
76
- const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
77
- const base64Data = imageData.toString("base64");
78
- return `data:image/png;base64,${base64Data}`;
79
- } catch (error) {
80
- console.error(error);
81
- return "";
82
- }
83
- } else
84
- return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.png`;
85
- }
86
- __name(getImageUrl, "getImageUrl");
87
- function getFormattedMatchData(match) {
88
- ["radiant", "dire"].forEach((team) => {
89
- match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
90
- });
91
- match.party = {};
92
- let party_index = 0;
93
- const party_mark = ["I", "II", "III", "IV"];
94
- let heroOrderList = {};
95
- for (let hero of match.pickBans) {
96
- if (hero.isPick)
97
- heroOrderList[hero.heroId] = hero.order;
98
- }
99
- let processLaneOutcome = /* @__PURE__ */ __name(function(outcome) {
100
- switch (outcome) {
101
- case "RADIANT_VICTORY":
102
- return { radiant: "victory", dire: "fail" };
103
- case "RADIANT_STOMP":
104
- return { radiant: "stomp", dire: "stomped" };
105
- case "DIRE_VICTORY":
106
- return { radiant: "fail", dire: "victory" };
107
- case "DIRE_STOMP":
108
- return { radiant: "stomped", dire: "stomp" };
109
- default:
110
- return { radiant: "tie", dire: "tie" };
111
- }
112
- }, "processLaneOutcome");
113
- let laneResult = { top: {}, mid: {}, bottom: {} };
114
- laneResult.top = processLaneOutcome(match.topLaneOutcome);
115
- laneResult.mid = processLaneOutcome(match.midLaneOutcome);
116
- laneResult.bottom = processLaneOutcome(match.bottomLaneOutcome);
117
- match.players.forEach((player) => {
118
- player.team = player.isRadiant ? "radiant" : "dire";
119
- player.rank = {
120
- medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
121
- star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
122
- leaderboard: player.steamAccount.seasonLeaderboardRank,
123
- inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
124
- };
125
- player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
126
- player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
127
- player.damageReceived = player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage;
128
- match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
129
- match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
130
- match[player.team].networth += player.networth;
131
- match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
132
- player.titles = [];
133
- player.mvpScore = // 计算MVP分数
134
- player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport.dealtTotal.stunDuration / 100 * 0.1 + (player.stats.heroDamageReport.dealtTotal.slowDuration + player.stats.heroDamageReport.dealtTotal.disableDuration) / 100 * 0.05 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
135
- player.order = heroOrderList[player.hero.id];
136
- if (player.partyId != null) {
137
- if (!match.party[player.partyId])
138
- match.party[player.partyId] = party_mark[party_index++];
139
- }
140
- const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
141
- const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
142
- if (!acc[key] || event.stackCount > acc[key].stackCount) {
143
- acc[key] = event;
144
- }
145
- return acc;
146
- }, {});
147
- player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
148
- switch (player.lane) {
149
- case "SAFE_LANE":
150
- player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
151
- break;
152
- case "OFF_LANE":
153
- player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.team];
154
- break;
155
- default:
156
- player.laneResult = laneResult.mid[player.team];
157
- break;
158
- }
159
- let items_timelist = {};
160
- player.supportItemsCount = { 30: 0, 40: 0, 42: 0, 43: 0, 188: 0 };
161
- if (player.playbackData) {
162
- for (let item of player.playbackData.purchaseEvents) {
163
- items_timelist[item.itemId] = item.time;
164
- if (item.itemId == 42 || item.itemId == 43)
165
- items_timelist[218] = item.time;
166
- switch (item.itemId) {
167
- case 30:
168
- case 40:
169
- case 42:
170
- case 43:
171
- case 188:
172
- player.supportItemsCount[item.itemId]++;
173
- break;
174
- }
175
- }
176
- }
177
- player.items = [];
178
- player.backpacks = [];
179
- const prefix = "recipe_";
180
- for (let i = 0; i <= 5; i++) {
181
- const key = `item${i}Id`;
182
- const itemId = player[key];
183
- if (itemId === void 0 || itemId === null) {
184
- player.items.push(null);
185
- } else if (dotaconstants.item_ids[itemId]) {
186
- const name2 = dotaconstants.item_ids[itemId];
187
- const isRecipe = name2.startsWith(prefix);
188
- const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
189
- player.items.push({
190
- id: itemId,
191
- name: cleanName,
192
- time: items_timelist[itemId],
193
- isRecipe
194
- });
195
- } else {
196
- player.items.push(null);
197
- }
198
- }
199
- for (let i = 0; i <= 2; i++) {
200
- const key = `backpack${i}Id`;
201
- const itemId = player[key];
202
- if (itemId === void 0 || itemId === null) {
203
- player.backpacks.push(null);
204
- } else if (dotaconstants.item_ids[itemId]) {
205
- const name2 = dotaconstants.item_ids[itemId];
206
- const isRecipe = name2.startsWith(prefix);
207
- const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
208
- player.backpacks.push({
209
- id: itemId,
210
- name: cleanName,
211
- time: items_timelist[itemId],
212
- isRecipe
213
- });
214
- } else {
215
- player.backpacks.push(null);
216
- }
217
- }
218
- if (player.additionalUnit) {
219
- player.unitItems = [];
220
- player.unitBackpacks = [];
221
- const prefix2 = "recipe_";
222
- for (let i = 0; i <= 5; i++) {
223
- const key = `item${i}Id`;
224
- const itemId = player.additionalUnit[key];
225
- if (itemId === void 0 || itemId === null) {
226
- player.unitItems.push(null);
227
- } else if (dotaconstants.item_ids[itemId]) {
228
- const name2 = dotaconstants.item_ids[itemId];
229
- const isRecipe = name2.startsWith(prefix2);
230
- const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
231
- player.unitItems.push({
232
- id: itemId,
233
- name: cleanName,
234
- time: items_timelist[itemId],
235
- isRecipe
236
- });
237
- } else {
238
- player.unitItems.push(null);
239
- }
240
- }
241
- for (let i = 0; i <= 2; i++) {
242
- const key = `backpack${i}Id`;
243
- const itemId = player.additionalUnit[key];
244
- if (itemId === void 0 || itemId === null) {
245
- player.unitBackpacks.push(null);
246
- } else if (dotaconstants.item_ids[itemId]) {
247
- const name2 = dotaconstants.item_ids[itemId];
248
- const isRecipe = name2.startsWith(prefix2);
249
- const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
250
- player.unitBackpacks.push({
251
- id: itemId,
252
- name: cleanName,
253
- time: items_timelist[itemId],
254
- isRecipe
255
- });
256
- } else {
257
- player.unitBackpacks.push(null);
258
- }
259
- }
260
- }
261
- });
262
- let ComparisonMode;
263
- ((ComparisonMode2) => {
264
- ComparisonMode2["Max"] = "max";
265
- ComparisonMode2["Min"] = "min";
266
- })(ComparisonMode || (ComparisonMode = {}));
267
- function findMaxByProperty(primaryProperty, secondaryProperty = null, players = match.players, primaryMode = "max" /* Max */, secondaryMode = "max" /* Max */) {
268
- return players.reduce((result, player) => {
269
- const primaryComparison = primaryMode === "max" /* Max */ ? player[primaryProperty] > result[primaryProperty] : player[primaryProperty] < result[primaryProperty];
270
- const secondaryComparison = secondaryMode === "max" /* Max */ ? player[secondaryProperty] > result[secondaryProperty] : player[secondaryProperty] < result[secondaryProperty];
271
- if (primaryComparison) {
272
- return player;
273
- } else if (player[primaryProperty] === result[primaryProperty] && secondaryProperty && secondaryComparison) {
274
- return player;
275
- }
276
- return result;
277
- });
278
- }
279
- __name(findMaxByProperty, "findMaxByProperty");
280
- findMaxByProperty(
281
- "mvpScore",
282
- void 0,
283
- match.players.filter((player) => match.didRadiantWin == player.isRadiant)
284
- ).titles.push({ name: "MVP", color: "#FFA500" });
285
- findMaxByProperty(
286
- "mvpScore",
287
- void 0,
288
- match.players.filter((player) => match.didRadiantWin != player.isRadiant)
289
- ).titles.push({ name: "魂", color: "#6cf" });
290
- findMaxByProperty("networth").titles.push({ name: "富", color: "#FFD700" });
291
- findMaxByProperty("experiencePerMinute").titles.push({ name: "睿", color: "#8888FF" });
292
- match.players.reduce(
293
- (max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration + player.stats.heroDamageReport.dealtTotal.slowDuration / 2 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration + max.stats.heroDamageReport.dealtTotal.slowDuration / 2 ? player : max
294
- ).titles.push({ name: "控", color: "#FF00FF" });
295
- findMaxByProperty("heroDamage").titles.push({ name: "爆", color: "#CC0088" });
296
- findMaxByProperty("kills", "heroDamage").titles.push({ name: "破", color: "#DD0000" });
297
- findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */).titles.push({ name: "鬼", color: "#CCCCCC" });
298
- findMaxByProperty("assists", "heroDamage").titles.push({ name: "助", color: "#006400" });
299
- findMaxByProperty("towerDamage", "heroDamage").titles.push({ name: "拆", color: "#FEDCBA" });
300
- findMaxByProperty("heroHealing").titles.push({ name: "奶", color: "#00FF00" });
301
- match.players.reduce(
302
- (max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
303
- ).titles.push({ name: "耐", color: "#84A1C7" });
304
- match.players.reduce((lowest, player) => {
305
- const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
306
- const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
307
- if (currentContribution < lowestContribution) {
308
- return player;
309
- } else if (currentContribution === lowestContribution) {
310
- const currentPlayerScore = player.kills + player.assists;
311
- const lowestPlayerScore = lowest.kills + lowest.assists;
312
- if (currentPlayerScore < lowestPlayerScore) {
313
- return player;
314
- } else if (currentPlayerScore === lowestPlayerScore) {
315
- return player.heroDamage < lowest.heroDamage ? player : lowest;
316
- }
317
- }
318
- return lowest;
319
- }).titles.push({ name: "摸", color: "#DDDDDD" });
320
- return match;
321
- }
322
- __name(getFormattedMatchData, "getFormattedMatchData");
58
+ var dotaconstants2 = __toESM(require("dotaconstants"));
59
+ var import_path = __toESM(require("path"));
323
60
 
324
61
  // src/queries.ts
325
- var dotaconstants2 = __toESM(require("dotaconstants"));
62
+ var dotaconstants = __toESM(require("dotaconstants"));
326
63
  function MATCH_INFO(matchId) {
327
64
  return `
328
65
  {
@@ -349,341 +86,665 @@ function MATCH_INFO(matchId) {
349
86
  steamAccount {
350
87
  name
351
88
  }
352
- level
353
- hero {
89
+ level
90
+ hero {
91
+ id
92
+ name
93
+ shortName
94
+ }
95
+ dotaPlus{
96
+ level
97
+ }
98
+ leaverStatus
99
+ partyId
100
+ position
101
+ lane
102
+ imp
103
+ kills
104
+ deaths
105
+ assists
106
+ isRadiant
107
+ networth
108
+ steamAccount {
109
+ seasonRank
110
+ seasonLeaderboardRank
111
+ }
112
+ item0Id
113
+ item1Id
114
+ item2Id
115
+ item3Id
116
+ item4Id
117
+ item5Id
118
+ backpack0Id
119
+ backpack1Id
120
+ backpack2Id
121
+ neutral0Id
122
+ stats {
123
+ matchPlayerBuffEvent {
124
+ abilityId
125
+ itemId
126
+ stackCount
127
+ }
128
+ }
129
+ playbackData {
130
+ purchaseEvents {
131
+ itemId
132
+ time
133
+ }
134
+ }
135
+ heroDamage
136
+ towerDamage
137
+ stats {
138
+ heroDamageReport {
139
+ receivedTotal {
140
+ physicalDamage
141
+ magicalDamage
142
+ pureDamage
143
+ }
144
+ }
145
+ }
146
+ numLastHits
147
+ numDenies
148
+ goldPerMinute
149
+ experiencePerMinute
150
+ heroHealing
151
+
152
+ stats {
153
+ campStack
154
+ heroDamageReport {
155
+ dealtTotal {
156
+ stunDuration
157
+ stunCount
158
+ slowDuration
159
+ slowCount
160
+ disableDuration
161
+ disableCount
162
+ }
163
+ }
164
+ }
165
+ additionalUnit{
166
+ item0Id
167
+ item1Id
168
+ item2Id
169
+ item3Id
170
+ item4Id
171
+ item5Id
172
+ backpack0Id
173
+ backpack1Id
174
+ backpack2Id
175
+ neutral0Id
176
+ }
177
+
178
+ isRandom
179
+ }
180
+ pickBans {
181
+ isPick
182
+ bannedHeroId
183
+ heroId
184
+ order
185
+ }
186
+ }
187
+ }
188
+
189
+ `;
190
+ }
191
+ __name(MATCH_INFO, "MATCH_INFO");
192
+ function VERIFYING_PLAYER(steamAccountId) {
193
+ return `
194
+ {
195
+ player(steamAccountId: ${steamAccountId}) {
196
+ matchCount
197
+ }
198
+ }
199
+
200
+ `;
201
+ }
202
+ __name(VERIFYING_PLAYER, "VERIFYING_PLAYER");
203
+ function PLAYERS_LASTMATCH(steamAccountIds) {
204
+ return `
205
+ {
206
+ players(steamAccountIds:${JSON.stringify(steamAccountIds)}) {
207
+ steamAccount{id}
208
+ matches(request:{take:1}){
209
+ id
210
+ parsedDateTime
211
+ startDateTime
212
+ }
213
+ }
214
+ }
215
+
216
+ `;
217
+ }
218
+ __name(PLAYERS_LASTMATCH, "PLAYERS_LASTMATCH");
219
+ function PLAYER_INFO_WITH_25_MATCHES(steamAccountId) {
220
+ return `
221
+ {
222
+ player(steamAccountId: ${steamAccountId}) {
223
+ steamAccount {
224
+ avatar
225
+ name
226
+ seasonRank
227
+ seasonLeaderboardRank
228
+ id
229
+ }
230
+ guildMember {
231
+ guild {
232
+ tag
233
+ }
234
+ }
235
+ matchCount
236
+ winCount
237
+ performance {
238
+ imp
239
+ }
240
+ heroesPerformance(take: 25, request: {matchGroupOrderBy: WIN_COUNT, take: 25}) {
241
+ hero {
242
+ id
243
+ shortName
244
+ }
245
+ imp
246
+ winCount
247
+ matchCount
248
+ }
249
+ matches(request: {take: 25}) {
250
+ id
251
+ rank
252
+ lobbyType
253
+ gameMode
254
+ endDateTime
255
+ durationSeconds
256
+ didRadiantWin
257
+ topLaneOutcome
258
+ midLaneOutcome
259
+ bottomLaneOutcome
260
+ radiantKills
261
+ direKills
262
+ players(steamAccountId: ${steamAccountId}) {
263
+ isRadiant
264
+ lane
265
+ kills
266
+ deaths
267
+ assists
268
+ position
269
+ award
270
+ imp
271
+ hero {
272
+ id
273
+ shortName
274
+ }
275
+ }
276
+ }
277
+ }
278
+
279
+ }
280
+
281
+ `;
282
+ }
283
+ __name(PLAYER_INFO_WITH_25_MATCHES, "PLAYER_INFO_WITH_25_MATCHES");
284
+ function PLAYER_EXTRA_INFO(steamAccountId, matchCount, totalHeroCount) {
285
+ return `{
286
+ player(steamAccountId: ${steamAccountId}) {
287
+ heroesPerformance(take: ${totalHeroCount}, request: {matchGroupOrderBy: MATCH_COUNT, take: ${matchCount}}) {
288
+ hero {
289
+ id
290
+ shortName
291
+ }
292
+ winCount
293
+ matchCount
294
+ imp
295
+ }
296
+ dotaPlus {
297
+ heroId
298
+ level
299
+ }
300
+ }
301
+ }
302
+ `;
303
+ }
304
+ __name(PLAYER_EXTRA_INFO, "PLAYER_EXTRA_INFO");
305
+ function CURRENT_GAMEVERSION() {
306
+ return `
307
+ {
308
+ constants {
309
+ gameVersions{name id}
310
+ }
311
+ }
312
+
313
+ `;
314
+ }
315
+ __name(CURRENT_GAMEVERSION, "CURRENT_GAMEVERSION");
316
+ function ALL_ABILITIES_CHINESE_NAME() {
317
+ return `
318
+ {
319
+ constants {
320
+ abilities(language:S_CHINESE){
321
+ id
322
+ language{displayName}
323
+ }
324
+ gameVersions{name id}
325
+ }
326
+ }
327
+
328
+ `;
329
+ }
330
+ __name(ALL_ABILITIES_CHINESE_NAME, "ALL_ABILITIES_CHINESE_NAME");
331
+ function HERO_INFO(heroId) {
332
+ return `
333
+ {
334
+ constants {
335
+ hero(id: ${heroId}, language: S_CHINESE) {
354
336
  id
355
337
  name
356
338
  shortName
357
- }
358
- dotaPlus{
359
- level
360
- }
361
- leaverStatus
362
- partyId
363
- position
364
- lane
365
- imp
366
- kills
367
- deaths
368
- assists
369
- isRadiant
370
- networth
371
- steamAccount {
372
- seasonRank
373
- seasonLeaderboardRank
374
- }
375
- item0Id
376
- item1Id
377
- item2Id
378
- item3Id
379
- item4Id
380
- item5Id
381
- backpack0Id
382
- backpack1Id
383
- backpack2Id
384
- neutral0Id
385
- stats {
386
- matchPlayerBuffEvent {
387
- abilityId
388
- itemId
389
- stackCount
339
+ aliases
340
+ roles {
341
+ roleId
342
+ level
390
343
  }
391
- }
392
- playbackData {
393
- purchaseEvents {
394
- itemId
395
- time
344
+ language {
345
+ displayName
346
+ lore
347
+ hype
396
348
  }
397
- }
398
- heroDamage
399
- towerDamage
400
- stats {
401
- heroDamageReport {
402
- receivedTotal {
403
- physicalDamage
404
- magicalDamage
405
- pureDamage
349
+ abilities {
350
+ ability(language: S_CHINESE) {
351
+ name
352
+ language {
353
+ displayName
354
+ description
355
+ attributes
356
+ lore
357
+ aghanimDescription
358
+ shardDescription
359
+ notes
360
+ }
361
+ stat {
362
+ type
363
+ behavior
364
+ unitTargetType
365
+ unitTargetTeam
366
+ unitTargetFlags
367
+ unitDamageType
368
+ cooldown
369
+ manaCost
370
+ spellImmunity
371
+ isOnCastbar
372
+ isGrantedByShard
373
+ isGrantedByScepter
374
+ hasShardUpgrade
375
+ hasScepterUpgrade
376
+ }
406
377
  }
407
378
  }
408
- }
409
- numLastHits
410
- numDenies
411
- goldPerMinute
412
- experiencePerMinute
413
- heroHealing
414
-
415
- stats {
416
- campStack
417
- heroDamageReport {
418
- dealtTotal {
419
- stunDuration
420
- stunCount
421
- slowDuration
422
- slowCount
423
- disableDuration
424
- disableCount
425
- }
379
+ talents {
380
+ abilityId
381
+ slot
426
382
  }
427
383
  }
428
- additionalUnit{
429
- item0Id
430
- item1Id
431
- item2Id
432
- item3Id
433
- item4Id
434
- item5Id
435
- backpack0Id
436
- backpack1Id
437
- backpack2Id
438
- neutral0Id
439
- }
440
-
441
- isRandom
442
384
  }
443
- pickBans {
444
- isPick
445
- bannedHeroId
446
- heroId
447
- order
385
+ }
386
+
387
+ `;
388
+ }
389
+ __name(HERO_INFO, "HERO_INFO");
390
+ function HERO_MATCHUP_WINRATE(heroId) {
391
+ return `
392
+ {
393
+ heroStats {
394
+ matchUp(heroId: ${heroId}, take: ${Object.keys(dotaconstants.heroes).length - 1},bracketBasicIds:LEGEND_ANCIENT) {
395
+ heroId
396
+ matchCountWith
397
+ matchCountVs
398
+ with {
399
+ heroId1
400
+ winRateHeroId1
401
+ heroId2
402
+ winRateHeroId2
403
+ winCount
404
+ matchCount
405
+ }
406
+ vs {
407
+ heroId1
408
+ winRateHeroId1
409
+ heroId2
410
+ winRateHeroId2
411
+ winCount
412
+ matchCount
413
+ }
414
+ }
448
415
  }
449
416
  }
417
+
418
+ `;
419
+ }
420
+ __name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
421
+
422
+ // src/utils.ts
423
+ var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
424
+ async function query(query_str) {
425
+ return await import_axios.default.post(CONFIGS.STRATZ_API.URL, query_str, {
426
+ headers: {
427
+ "Content-Type": "application/graphql",
428
+ Authorization: `Bearer ${CONFIGS.STRATZ_API.TOKEN}`
429
+ }
430
+ });
431
+ }
432
+ __name(query, "query");
433
+ var ImageType = /* @__PURE__ */ ((ImageType2) => {
434
+ ImageType2["Icons"] = "icons";
435
+ ImageType2["Heroes"] = "heroes";
436
+ ImageType2["HeroIcons"] = "heroes/icons";
437
+ ImageType2["Items"] = "items";
438
+ ImageType2["Abilities"] = "abilities";
439
+ ImageType2["Local"] = "local";
440
+ return ImageType2;
441
+ })(ImageType || {});
442
+ function getImageUrl(image, type = "local" /* Local */) {
443
+ if (type === "local" /* Local */) {
444
+ try {
445
+ const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
446
+ const base64Data = imageData.toString("base64");
447
+ return `data:image/png;base64,${base64Data}`;
448
+ } catch (error) {
449
+ console.error(error);
450
+ return "";
451
+ }
452
+ } else
453
+ return `https://cdn.cloudflare.steamstatic.com/apps/dota2/images/dota_react/${type}/${image}.png`;
454
+ }
455
+ __name(getImageUrl, "getImageUrl");
456
+ function getFormattedMatchData(match) {
457
+ ["radiant", "dire"].forEach((team) => {
458
+ match[team] = { killsCount: match[team + "Kills"]?.reduce((acc, cva) => acc + cva, 0) ?? 0, damageReceived: 0, heroDamage: 0, networth: 0, experience: 0 };
459
+ });
460
+ match.party = {};
461
+ let party_index = 0;
462
+ const party_mark = ["I", "II", "III", "IV"];
463
+ let heroOrderList = {};
464
+ for (let hero of match.pickBans) {
465
+ if (hero.isPick)
466
+ heroOrderList[hero.heroId] = hero.order;
467
+ }
468
+ let processLaneOutcome = /* @__PURE__ */ __name(function(outcome) {
469
+ switch (outcome) {
470
+ case "RADIANT_VICTORY":
471
+ return { radiant: "victory", dire: "fail" };
472
+ case "RADIANT_STOMP":
473
+ return { radiant: "stomp", dire: "stomped" };
474
+ case "DIRE_VICTORY":
475
+ return { radiant: "fail", dire: "victory" };
476
+ case "DIRE_STOMP":
477
+ return { radiant: "stomped", dire: "stomp" };
478
+ default:
479
+ return { radiant: "tie", dire: "tie" };
480
+ }
481
+ }, "processLaneOutcome");
482
+ let laneResult = { top: {}, mid: {}, bottom: {} };
483
+ laneResult.top = processLaneOutcome(match.topLaneOutcome);
484
+ laneResult.mid = processLaneOutcome(match.midLaneOutcome);
485
+ laneResult.bottom = processLaneOutcome(match.bottomLaneOutcome);
486
+ match.players.forEach((player) => {
487
+ player.team = player.isRadiant ? "radiant" : "dire";
488
+ player.rank = {
489
+ medal: parseInt(player.steamAccount.seasonRank?.toString().split("")[0] ?? 0),
490
+ star: parseInt(player.steamAccount.seasonRank?.toString().split("")[1] ?? 0),
491
+ leaderboard: player.steamAccount.seasonLeaderboardRank,
492
+ inTop100: player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : player.steamAccount.seasonLeaderboardRank <= 100 ? "8b" : void 0 : void 0
493
+ };
494
+ player.killContribution = (player.kills + player.assists) / match[player.team].killsCount;
495
+ player.deathContribution = player.deaths / match[player.team === "radiant" ? "dire" : player.team].killsCount;
496
+ player.damageReceived = player.stats?.heroDamageReport?.receivedTotal.physicalDamage + player.stats?.heroDamageReport?.receivedTotal.magicalDamage + player.stats?.heroDamageReport?.receivedTotal.pureDamage;
497
+ match[player.team].heroDamage = (match[player.team].heroDamage ?? 0) + player.heroDamage;
498
+ match[player.team].damageReceived = (match[player.team].damageReceived ?? 0) + player.damageReceived;
499
+ match[player.team].networth += player.networth;
500
+ match[player.team].experience += Math.floor(player.experiencePerMinute / 60 * match.durationSeconds);
501
+ player.titles = [];
502
+ player.mvpScore = // 计算MVP分数
503
+ player.kills * 5 + player.assists * 3 + player.stats.heroDamageReport.dealtTotal.stunDuration / 100 * 0.1 + (player.stats.heroDamageReport.dealtTotal.slowDuration + player.stats.heroDamageReport.dealtTotal.disableDuration) / 100 * 0.05 + player.heroDamage * 1e-3 + player.towerDamage * 0.01 + player.heroHealing * 2e-3 + player.imp * 0.25;
504
+ player.order = heroOrderList[player.hero.id];
505
+ if (player.partyId != null) {
506
+ if (!match.party[player.partyId])
507
+ match.party[player.partyId] = party_mark[party_index++];
508
+ }
509
+ const maxStackCountsByAbilityOrItem = player.stats.matchPlayerBuffEvent.reduce((acc, event) => {
510
+ const key = event.abilityId !== null ? `ability-${event.abilityId}` : `item-${event.itemId}`;
511
+ if (!acc[key] || event.stackCount > acc[key].stackCount) {
512
+ acc[key] = event;
513
+ }
514
+ return acc;
515
+ }, {});
516
+ player.stats.matchPlayerBuffEvent.splice(0, player.stats.matchPlayerBuffEvent.length, ...Object.values(maxStackCountsByAbilityOrItem));
517
+ switch (player.lane) {
518
+ case "SAFE_LANE":
519
+ player.laneResult = laneResult[player.isRadiant ? "bottom" : "top"][player.team];
520
+ break;
521
+ case "OFF_LANE":
522
+ player.laneResult = laneResult[!player.isRadiant ? "bottom" : "top"][player.team];
523
+ break;
524
+ default:
525
+ player.laneResult = laneResult.mid[player.team];
526
+ break;
450
527
  }
451
-
452
- `;
453
- }
454
- __name(MATCH_INFO, "MATCH_INFO");
455
- function VERIFYING_PLAYER(steamAccountId) {
456
- return `
457
- {
458
- player(steamAccountId: ${steamAccountId}) {
459
- matchCount
528
+ let items_timelist = {};
529
+ player.supportItemsCount = { 30: 0, 40: 0, 42: 0, 43: 0, 188: 0 };
530
+ if (player.playbackData) {
531
+ for (let item of player.playbackData.purchaseEvents) {
532
+ items_timelist[item.itemId] = item.time;
533
+ if (item.itemId == 42 || item.itemId == 43)
534
+ items_timelist[218] = item.time;
535
+ switch (item.itemId) {
536
+ case 30:
537
+ case 40:
538
+ case 42:
539
+ case 43:
540
+ case 188:
541
+ player.supportItemsCount[item.itemId]++;
542
+ break;
460
543
  }
461
544
  }
462
-
463
- `;
464
- }
465
- __name(VERIFYING_PLAYER, "VERIFYING_PLAYER");
466
- function PLAYERS_LASTMATCH(steamAccountIds) {
467
- return `
468
- {
469
- players(steamAccountIds:${JSON.stringify(steamAccountIds)}) {
470
- steamAccount{id}
471
- matches(request:{take:1}){
472
- id
473
- parsedDateTime
474
- startDateTime
475
- }
545
+ }
546
+ player.items = [];
547
+ player.backpacks = [];
548
+ const prefix = "recipe_";
549
+ for (let i = 0; i <= 5; i++) {
550
+ const key = `item${i}Id`;
551
+ const itemId = player[key];
552
+ if (itemId === void 0 || itemId === null) {
553
+ player.items.push(null);
554
+ } else if (dotaconstants2.item_ids[itemId]) {
555
+ const name2 = dotaconstants2.item_ids[itemId];
556
+ const isRecipe = name2.startsWith(prefix);
557
+ const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
558
+ player.items.push({
559
+ id: itemId,
560
+ name: cleanName,
561
+ time: items_timelist[itemId],
562
+ isRecipe
563
+ });
564
+ } else {
565
+ player.items.push(null);
566
+ }
567
+ }
568
+ for (let i = 0; i <= 2; i++) {
569
+ const key = `backpack${i}Id`;
570
+ const itemId = player[key];
571
+ if (itemId === void 0 || itemId === null) {
572
+ player.backpacks.push(null);
573
+ } else if (dotaconstants2.item_ids[itemId]) {
574
+ const name2 = dotaconstants2.item_ids[itemId];
575
+ const isRecipe = name2.startsWith(prefix);
576
+ const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
577
+ player.backpacks.push({
578
+ id: itemId,
579
+ name: cleanName,
580
+ time: items_timelist[itemId],
581
+ isRecipe
582
+ });
583
+ } else {
584
+ player.backpacks.push(null);
585
+ }
586
+ }
587
+ if (player.additionalUnit) {
588
+ player.unitItems = [];
589
+ player.unitBackpacks = [];
590
+ const prefix2 = "recipe_";
591
+ for (let i = 0; i <= 5; i++) {
592
+ const key = `item${i}Id`;
593
+ const itemId = player.additionalUnit[key];
594
+ if (itemId === void 0 || itemId === null) {
595
+ player.unitItems.push(null);
596
+ } else if (dotaconstants2.item_ids[itemId]) {
597
+ const name2 = dotaconstants2.item_ids[itemId];
598
+ const isRecipe = name2.startsWith(prefix2);
599
+ const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
600
+ player.unitItems.push({
601
+ id: itemId,
602
+ name: cleanName,
603
+ time: items_timelist[itemId],
604
+ isRecipe
605
+ });
606
+ } else {
607
+ player.unitItems.push(null);
476
608
  }
477
609
  }
478
-
479
- `;
480
- }
481
- __name(PLAYERS_LASTMATCH, "PLAYERS_LASTMATCH");
482
- function PLAYER_INFO_WITH_25_MATCHES(steamAccountId) {
483
- return `
484
- {
485
- player(steamAccountId: ${steamAccountId}) {
486
- steamAccount {
487
- avatar
488
- name
489
- seasonRank
490
- seasonLeaderboardRank
491
- id
492
- }
493
- guildMember {
494
- guild {
495
- tag
496
- }
497
- }
498
- matchCount
499
- winCount
500
- performance {
501
- imp
502
- }
503
- heroesPerformance(take: 25, request: {matchGroupOrderBy: WIN_COUNT, take: 25}) {
504
- hero {
505
- id
506
- shortName
507
- }
508
- imp
509
- winCount
510
- matchCount
511
- }
512
- matches(request: {take: 25}) {
513
- id
514
- rank
515
- lobbyType
516
- gameMode
517
- endDateTime
518
- durationSeconds
519
- didRadiantWin
520
- topLaneOutcome
521
- midLaneOutcome
522
- bottomLaneOutcome
523
- radiantKills
524
- direKills
525
- players(steamAccountId: ${steamAccountId}) {
526
- isRadiant
527
- lane
528
- kills
529
- deaths
530
- assists
531
- award
532
- imp
533
- hero {
534
- id
535
- shortName
536
- }
537
- }
538
- }
539
- }
540
-
541
- }
542
-
543
- `;
544
- }
545
- __name(PLAYER_INFO_WITH_25_MATCHES, "PLAYER_INFO_WITH_25_MATCHES");
546
- function PLAYER_EXTRA_INFO(steamAccountId, matchCount, totalHeroCount) {
547
- return `{
548
- player(steamAccountId: ${steamAccountId}) {
549
- heroesPerformance(take: ${totalHeroCount}, request: {matchGroupOrderBy: MATCH_COUNT, take: ${matchCount}}) {
550
- hero {
551
- id
552
- shortName
553
- }
554
- winCount
555
- matchCount
556
- imp
557
- }
558
- dotaPlus {
559
- heroId
560
- level
561
- }
610
+ for (let i = 0; i <= 2; i++) {
611
+ const key = `backpack${i}Id`;
612
+ const itemId = player.additionalUnit[key];
613
+ if (itemId === void 0 || itemId === null) {
614
+ player.unitBackpacks.push(null);
615
+ } else if (dotaconstants2.item_ids[itemId]) {
616
+ const name2 = dotaconstants2.item_ids[itemId];
617
+ const isRecipe = name2.startsWith(prefix2);
618
+ const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
619
+ player.unitBackpacks.push({
620
+ id: itemId,
621
+ name: cleanName,
622
+ time: items_timelist[itemId],
623
+ isRecipe
624
+ });
625
+ } else {
626
+ player.unitBackpacks.push(null);
562
627
  }
563
628
  }
564
- `;
629
+ }
630
+ });
631
+ let ComparisonMode;
632
+ ((ComparisonMode2) => {
633
+ ComparisonMode2["Max"] = "max";
634
+ ComparisonMode2["Min"] = "min";
635
+ })(ComparisonMode || (ComparisonMode = {}));
636
+ function findMaxByProperty(primaryProperty, secondaryProperty = null, players = match.players, primaryMode = "max" /* Max */, secondaryMode = "max" /* Max */) {
637
+ return players.reduce((result, player) => {
638
+ const primaryComparison = primaryMode === "max" /* Max */ ? player[primaryProperty] > result[primaryProperty] : player[primaryProperty] < result[primaryProperty];
639
+ const secondaryComparison = secondaryMode === "max" /* Max */ ? player[secondaryProperty] > result[secondaryProperty] : player[secondaryProperty] < result[secondaryProperty];
640
+ if (primaryComparison) {
641
+ return player;
642
+ } else if (player[primaryProperty] === result[primaryProperty] && secondaryProperty && secondaryComparison) {
643
+ return player;
644
+ }
645
+ return result;
646
+ });
647
+ }
648
+ __name(findMaxByProperty, "findMaxByProperty");
649
+ findMaxByProperty(
650
+ "mvpScore",
651
+ void 0,
652
+ match.players.filter((player) => match.didRadiantWin == player.isRadiant)
653
+ ).titles.push({ name: "MVP", color: "#FFA500" });
654
+ findMaxByProperty(
655
+ "mvpScore",
656
+ void 0,
657
+ match.players.filter((player) => match.didRadiantWin != player.isRadiant)
658
+ ).titles.push({ name: "魂", color: "#6cf" });
659
+ findMaxByProperty("networth").titles.push({ name: "富", color: "#FFD700" });
660
+ findMaxByProperty("experiencePerMinute").titles.push({ name: "睿", color: "#8888FF" });
661
+ match.players.reduce(
662
+ (max, player) => player.stats.heroDamageReport.dealtTotal.stunDuration + player.stats.heroDamageReport.dealtTotal.disableDuration + player.stats.heroDamageReport.dealtTotal.slowDuration / 2 > max.stats.heroDamageReport.dealtTotal.stunDuration + max.stats.heroDamageReport.dealtTotal.disableDuration + max.stats.heroDamageReport.dealtTotal.slowDuration / 2 ? player : max
663
+ ).titles.push({ name: "控", color: "#FF00FF" });
664
+ findMaxByProperty("heroDamage").titles.push({ name: "爆", color: "#CC0088" });
665
+ findMaxByProperty("kills", "heroDamage").titles.push({ name: "破", color: "#DD0000" });
666
+ findMaxByProperty("deaths", "networth", void 0, void 0, "min" /* Min */).titles.push({ name: "鬼", color: "#CCCCCC" });
667
+ findMaxByProperty("assists", "heroDamage").titles.push({ name: "助", color: "#006400" });
668
+ findMaxByProperty("towerDamage", "heroDamage").titles.push({ name: "拆", color: "#FEDCBA" });
669
+ findMaxByProperty("heroHealing").titles.push({ name: "奶", color: "#00FF00" });
670
+ match.players.reduce(
671
+ (max, player) => player.stats.heroDamageReport.receivedTotal.physicalDamage + player.stats.heroDamageReport.receivedTotal.magicalDamage + player.stats.heroDamageReport.receivedTotal.pureDamage > max.stats.heroDamageReport.receivedTotal.physicalDamage + max.stats.heroDamageReport.receivedTotal.magicalDamage + max.stats.heroDamageReport.receivedTotal.pureDamage ? player : max
672
+ ).titles.push({ name: "耐", color: "#84A1C7" });
673
+ match.players.reduce((lowest, player) => {
674
+ const currentContribution = (player.kills + player.assists) / match[player.team].KillsCount;
675
+ const lowestContribution = (lowest.kills + lowest.assists) / match[lowest.team].KillsCount;
676
+ if (currentContribution < lowestContribution) {
677
+ return player;
678
+ } else if (currentContribution === lowestContribution) {
679
+ const currentPlayerScore = player.kills + player.assists;
680
+ const lowestPlayerScore = lowest.kills + lowest.assists;
681
+ if (currentPlayerScore < lowestPlayerScore) {
682
+ return player;
683
+ } else if (currentPlayerScore === lowestPlayerScore) {
684
+ return player.heroDamage < lowest.heroDamage ? player : lowest;
685
+ }
686
+ }
687
+ return lowest;
688
+ }).titles.push({ name: "摸", color: "#DDDDDD" });
689
+ return match;
565
690
  }
566
- __name(PLAYER_EXTRA_INFO, "PLAYER_EXTRA_INFO");
567
- function CURRENT_GAMEVERSION() {
568
- return `
569
- {
570
- constants {
571
- gameVersions{name id}
572
- }
573
- }
574
-
575
- `;
691
+ __name(getFormattedMatchData, "getFormattedMatchData");
692
+ function sec2time(sec) {
693
+ return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
576
694
  }
577
- __name(CURRENT_GAMEVERSION, "CURRENT_GAMEVERSION");
578
- function ALL_ABILITIES_CHINESE_NAME() {
579
- return `
580
- {
581
- constants {
582
- abilities(language:S_CHINESE){
583
- id
584
- language{displayName}
585
- }
586
- gameVersions{name id}
587
- }
588
- }
589
-
590
- `;
695
+ __name(sec2time, "sec2time");
696
+ function formatNumber(num) {
697
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
591
698
  }
592
- __name(ALL_ABILITIES_CHINESE_NAME, "ALL_ABILITIES_CHINESE_NAME");
593
- function HERO_INFO(heroId) {
594
- return `
595
- {
596
- constants {
597
- hero(id: ${heroId}, language: S_CHINESE) {
598
- id
599
- name
600
- shortName
601
- aliases
602
- roles {
603
- roleId
604
- level
605
- }
606
- language {
607
- displayName
608
- lore
609
- hype
610
- }
611
- abilities {
612
- ability(language: S_CHINESE) {
613
- name
614
- language {
615
- displayName
616
- description
617
- attributes
618
- lore
619
- aghanimDescription
620
- shardDescription
621
- notes
622
- }
623
- stat {
624
- type
625
- behavior
626
- unitTargetType
627
- unitTargetTeam
628
- unitTargetFlags
629
- unitDamageType
630
- cooldown
631
- manaCost
632
- spellImmunity
633
- isOnCastbar
634
- isGrantedByShard
635
- isGrantedByScepter
636
- hasShardUpgrade
637
- hasScepterUpgrade
638
- }
639
- }
640
- }
641
- talents {
642
- abilityId
643
- slot
644
- }
645
- }
646
- }
647
- }
648
-
649
- `;
699
+ __name(formatNumber, "formatNumber");
700
+ function readDirectoryFilesSync(directoryPath) {
701
+ try {
702
+ const files = import_fs.default.readdirSync(directoryPath);
703
+ const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
704
+ return fileNames;
705
+ } catch (error) {
706
+ console.error("Error reading directory:", error);
707
+ return [];
708
+ }
650
709
  }
651
- __name(HERO_INFO, "HERO_INFO");
652
- function HERO_MATCHUP_WINRATE(heroId) {
653
- return `
654
- {
655
- heroStats {
656
- matchUp(heroId: ${heroId}, take: ${Object.keys(dotaconstants2.heroes).length - 1},bracketBasicIds:LEGEND_ANCIENT) {
657
- heroId
658
- matchCountWith
659
- matchCountVs
660
- with {
661
- heroId1
662
- winRateHeroId1
663
- heroId2
664
- winRateHeroId2
665
- winCount
666
- matchCount
667
- }
668
- vs {
669
- heroId1
670
- winRateHeroId1
671
- heroId2
672
- winRateHeroId2
673
- winCount
674
- matchCount
675
- }
676
- }
677
- }
678
- }
679
-
680
- `;
710
+ __name(readDirectoryFilesSync, "readDirectoryFilesSync");
711
+ function winRateColor(value) {
712
+ value = value * 100;
713
+ value = Math.max(0, Math.min(100, value));
714
+ let red, green, blue;
715
+ if (value <= 50) {
716
+ let scale = Math.round(255 * (value / 50));
717
+ red = 255;
718
+ green = scale;
719
+ blue = scale;
720
+ } else {
721
+ let scale = Math.round(255 * ((value - 50) / 50));
722
+ red = 255 - scale;
723
+ green = 255;
724
+ blue = 255 - scale;
725
+ }
726
+ const toHex = /* @__PURE__ */ __name((color) => color.toString(16).padStart(2, "0").toUpperCase(), "toHex");
727
+ return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
681
728
  }
682
- __name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
729
+ __name(winRateColor, "winRateColor");
730
+ async function playerisValid(steamAccountId) {
731
+ try {
732
+ let queryRes = await query(VERIFYING_PLAYER(steamAccountId));
733
+ if (queryRes.status == 200) {
734
+ if (queryRes.data.data.player.matchCount != null)
735
+ return { isValid: true };
736
+ else
737
+ return { isValid: false, reason: "SteamID无效或无任何场次。" };
738
+ }
739
+ } catch (error) {
740
+ console.error(error);
741
+ return { isValid: false, reason: "网络状况不佳SteamID验证失败,请稍后重试。" };
742
+ }
743
+ }
744
+ __name(playerisValid, "playerisValid");
683
745
 
684
746
  // src/index.ts
685
747
  var import_fs2 = __toESM(require("fs"));
686
- var cheerio = __toESM(require("cheerio"));
687
748
  var import_moment = __toESM(require("moment"));
688
749
  var dotaconstants3 = __toESM(require("dotaconstants"));
689
750
 
@@ -956,14 +1017,20 @@ var dotaconstants_add_default = {
956
1017
  // src/index.ts
957
1018
  var import_koishi2 = require("koishi");
958
1019
  var ejs = __toESM(require("ejs"));
959
- var import_path = __toESM(require("path"));
1020
+ var import_path2 = __toESM(require("path"));
960
1021
  var name = "dota2tracker";
961
1022
  var usage = "DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。";
962
1023
  var inject = ["database", "puppeteer", "cron"];
963
- var Config = import_koishi.Schema.object({
964
- STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取"),
965
- 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 有模板展示。")
966
- });
1024
+ var Config = import_koishi.Schema.intersect([
1025
+ import_koishi.Schema.object({
1026
+ STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取")
1027
+ }).description("基础设置"),
1028
+ import_koishi.Schema.object({
1029
+ 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 有模板展示。"),
1030
+ template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1").description("生成玩家信息图片使用的模板。(目前仅有一张模板)"),
1031
+ template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1").description("生成英雄信息图片使用的模板。(目前仅有一张模板)")
1032
+ }).description("模板设置")
1033
+ ]);
967
1034
  var pendingMatches = [];
968
1035
  var random = new import_koishi2.Random(() => Math.random());
969
1036
  async function apply(ctx, config) {
@@ -1008,8 +1075,8 @@ async function apply(ctx, config) {
1008
1075
  );
1009
1076
  return;
1010
1077
  }
1011
- let verifyRes = await playerIsInvalid(steam_id);
1012
- if (!verifyRes.isInvalid) {
1078
+ let verifyRes = await playerisValid(steam_id);
1079
+ if (!verifyRes.isValid) {
1013
1080
  session.send(`绑定失败,${verifyRes.reason}`);
1014
1081
  return;
1015
1082
  }
@@ -1069,7 +1136,7 @@ async function apply(ctx, config) {
1069
1136
  }
1070
1137
  }
1071
1138
  if (match && match.parsedDateTime) {
1072
- session.send(await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match)));
1139
+ session.send(await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */)));
1073
1140
  ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
1074
1141
  } else {
1075
1142
  pendingMatches.push({ matchId, platform: session.event.platform, guildId: session.event.guild.id });
@@ -1175,7 +1242,7 @@ async function apply(ctx, config) {
1175
1242
  player.heroesPerformanceTop10 = playerExtra.heroesPerformance.slice(0, 10);
1176
1243
  } else
1177
1244
  throw 0;
1178
- session.send(await ctx.puppeteer.render(genPlayerHTML(player)));
1245
+ session.send(await ctx.puppeteer.render(genImageHTML(player, config.template_player, "player" /* Player */)));
1179
1246
  } catch (error) {
1180
1247
  console.error(error);
1181
1248
  session.send("获取玩家信息失败。");
@@ -1228,7 +1295,7 @@ async function apply(ctx, config) {
1228
1295
  if (queryRes3.status == 200) {
1229
1296
  let hero = queryRes3.data.data.constants.hero;
1230
1297
  hero.talents.forEach((talent) => talent.name_cn = AbilitiesConstantsCN.data.abilities.find((item) => item.id == talent.abilityId).language.displayName);
1231
- await session.send(await ctx.puppeteer.render(genHeroHTML(hero)));
1298
+ await session.send(await ctx.puppeteer.render(genImageHTML(hero, config.template_hero, "hero" /* Hero */)));
1232
1299
  } else
1233
1300
  throw 0;
1234
1301
  } catch (error) {
@@ -1355,7 +1422,7 @@ async function apply(ctx, config) {
1355
1422
  const commingMatches = scanningMatches.filter((item) => item.matchId == match.id);
1356
1423
  const realCommingMatches = commingMatches.filter((commingMatch, index, self) => index === self.findIndex((t) => t.guildId === commingMatch.guildId && t.platform === commingMatch.platform));
1357
1424
  let broadMatchMessage = "";
1358
- const img = await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match));
1425
+ const img = await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */));
1359
1426
  for (let comming of realCommingMatches) {
1360
1427
  let commingSubscribedPlayers = subscribedPlayersInGuild.filter((item) => item.platform == comming.platform && item.guildId == comming.guildId);
1361
1428
  let idsToFind = commingSubscribedPlayers.map((item) => item.steamId);
@@ -1394,20 +1461,18 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1394
1461
  });
1395
1462
  }
1396
1463
  __name(apply, "apply");
1397
- function newGenMatchImageHTML(match, template = "match_1") {
1398
- const templatePath = import_path.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/match`, template + ".ejs");
1399
- const data = {
1400
- match,
1464
+ function genImageHTML(data, template, type) {
1465
+ const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
1466
+ const templateData = {
1467
+ data,
1401
1468
  utils: utils_exports,
1402
1469
  ImageType,
1403
1470
  d2a: dotaconstants_add_exports,
1404
1471
  dotaconstants: dotaconstants3,
1405
- moment: import_moment.default,
1406
- sec2time,
1407
- formatNumber
1472
+ moment: import_moment.default
1408
1473
  };
1409
1474
  let result = "";
1410
- ejs.renderFile(templatePath, data, (err, html) => {
1475
+ ejs.renderFile(templatePath, templateData, (err, html) => {
1411
1476
  if (err)
1412
1477
  throw err;
1413
1478
  else
@@ -1417,380 +1482,7 @@ function newGenMatchImageHTML(match, template = "match_1") {
1417
1482
  import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", result);
1418
1483
  return result;
1419
1484
  }
1420
- __name(newGenMatchImageHTML, "newGenMatchImageHTML");
1421
- function genHeroHTML(hero) {
1422
- let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero.html`, "utf-8"));
1423
- let html = `
1424
- <div class="hero" id="${hero.id}">
1425
- <img src="${getImageUrl(hero.shortName, "heroes" /* Heroes */)}" alt="" />
1426
- <img class="pri_attr" src="${getImageUrl(primary_attrs[dotaconstants3.heroes[hero.id].primary_attr], "icons" /* Icons */)}" alt="" />
1427
- <div class="info">
1428
- <p class="name">${hero.language.displayName}</p>
1429
- <p class="roles">
1430
- ${hero.roles.map((item) => `<span class="role level${item.level}">${roles[item.roleId]}</span>`).join("")}
1431
- </p>
1432
- <p class="attrs">
1433
- <span class="str">${dotaconstants3.heroes[hero.id].base_str} <span class="gain">+${dotaconstants3.heroes[hero.id].str_gain.toFixed(1)}</span></span>
1434
- <span class="agi">${dotaconstants3.heroes[hero.id].base_agi} <span class="gain">+${dotaconstants3.heroes[hero.id].agi_gain.toFixed(1)}</span></span>
1435
- <span class="int">${dotaconstants3.heroes[hero.id].base_int} <span class="gain">+${dotaconstants3.heroes[hero.id].int_gain.toFixed(1)}</span></span>
1436
- </p>
1437
- </div>
1438
- </div>
1439
- <div class="details">
1440
- <div class="hype_talents">
1441
- <div class="hype">
1442
- ${hero.language.hype}
1443
- </div>
1444
- <div class="talents">
1445
- <div class="talent">
1446
- <div class="left">${hero.talents[7].name_cn}</div>
1447
- <div class="level">25</div>
1448
- <div class="right">${hero.talents[6].name_cn}</div>
1449
- </div>
1450
- <div class="talent">
1451
- <div class="left">${hero.talents[5].name_cn}</div>
1452
- <div class="level">20</div>
1453
- <div class="right">${hero.talents[4].name_cn}</div>
1454
- </div>
1455
- <div class="talent">
1456
- <div class="left">${hero.talents[3].name_cn}</div>
1457
- <div class="level">15</div>
1458
- <div class="right">${hero.talents[2].name_cn}</div>
1459
- </div>
1460
- <div class="talent">
1461
- <div class="left">${hero.talents[1].name_cn}</div>
1462
- <div class="level">10</div>
1463
- <div class="right">${hero.talents[0].name_cn}</div>
1464
- </div>
1465
- </div>
1466
- </div>
1467
- <table class="list">
1468
- <tbody>
1469
- <tr>
1470
- <td>初始生命值</td>
1471
- <td>${dotaconstants3.heroes[hero.id].base_health + dotaconstants3.heroes[hero.id].base_str * 22}</td>
1472
- </tr>
1473
- <tr>
1474
- <td>初始生命回复</td>
1475
- <td>${dotaconstants3.heroes[hero.id].base_health_regen}</td>
1476
- </tr>
1477
- <tr>
1478
- <td>初始魔法值</td>
1479
- <td>${dotaconstants3.heroes[hero.id].base_mana + dotaconstants3.heroes[hero.id].base_int * 12}</td>
1480
- </tr>
1481
- <tr>
1482
- <td>初始魔法回复</td>
1483
- <td>${dotaconstants3.heroes[hero.id].base_mana_regen}</td>
1484
- </tr>
1485
- <tr>
1486
- <td>初始攻击力</td>
1487
- <td>${dotaconstants3.heroes[hero.id].base_mr + Math.round(
1488
- dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
1489
- )}(${dotaconstants3.heroes[hero.id].base_attack_min + Math.round(
1490
- dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
1491
- )}~${dotaconstants3.heroes[hero.id].base_attack_max + Math.round(
1492
- dotaconstants3.heroes[hero.id].primary_attr == "all" ? (dotaconstants3.heroes[hero.id].base_str + dotaconstants3.heroes[hero.id].base_agi + dotaconstants3.heroes[hero.id].base_int) * 0.7 : dotaconstants3.heroes[hero.id]["base_" + dotaconstants3.heroes[hero.id].primary_attr]
1493
- )})</td>
1494
- </tr>
1495
- <tr>
1496
- <td>基础攻击间隔</td>
1497
- <td>${dotaconstants3.heroes[hero.id].attack_rate.toFixed(1)}</td>
1498
- </tr>
1499
- <tr>
1500
- <td>基础攻击前摇</td>
1501
- <td>${dotaconstants3.heroes[hero.id].attack_point.toFixed(1)}</td>
1502
- </tr>
1503
- <tr>
1504
- <td>攻击范围</td>
1505
- <td>${dotaconstants3.heroes[hero.id].attack_range}</td>
1506
- </tr>
1507
- <tr>
1508
- <td>护甲</td>
1509
- <td>${(Math.round((dotaconstants3.heroes[hero.id].base_armor + dotaconstants3.heroes[hero.id].base_agi * 0.167) * 10) / 10).toFixed(1)}</td>
1510
- </tr>
1511
- <tr>
1512
- <td>移动速度</td>
1513
- <td>${dotaconstants3.heroes[hero.id].move_speed}</td>
1514
- </tr>
1515
- <tr>
1516
- <td>视野范围</td>
1517
- <td>${dotaconstants3.heroes[hero.id].day_vision}(${dotaconstants3.heroes[hero.id].night_vision})</td>
1518
- </tr>
1519
- </tbody>
1520
- </table>
1521
- </div>
1522
- <div class="skills">
1523
- ${hero.abilities.filter((item) => dotaconstants3.abilities[item.ability.name].behavior != "Hidden").map(
1524
- (item) => `
1525
- <div class="skill">
1526
- <p class="title">${item.ability.language.displayName}</p>
1527
- ${item.ability.stat.isGrantedByScepter ? `<svg class="scepter" viewBox="0 0 19 20" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M4.795 14.99a2.06 2.06 0 00-.96-.388c-1.668-.204-2.506.518-3.107 1.008.464.128.879.364.867.97 2.347-1.605 4.159.84 2.415 2.666-.14.147.65.929.767.718.203-.365.79-1.064 1.445-1.064.964 0 1.529.68 1.823.838.267.144.793-.372.642-.675-.03-.06-.229-.204-.569-.438-1.407-.197-1.935-1.093-2.37-2.026-.276-.593-.503-1.206-.953-1.61zm9.41 0a2.06 2.06 0 01.96-.388c1.668-.204 2.507.518 3.107 1.008-.464.128-.879.364-.867.97-2.347-1.605-4.158.84-2.415 2.666.14.147-.65.929-.768.718-.202-.365-.79-1.064-1.444-1.064-.965 0-1.529.68-1.823.838-.267.144-.793-.372-.642-.675.03-.06.229-.204.569-.438 1.407-.197 1.935-1.093 2.37-2.026.276-.593.503-1.206.953-1.61zm-3.919-2.211c0-.233-.175-.423-.392-.423h-.788c-.217 0-.392.19-.392.423v5.665c0 .232.175.421.392.421h.788c.216 0 .392-.189.392-.421v-5.665zm-1.989 2.543c-.553-.139-2.074-.563-2.702-1.17-.814-.784-1.107-3.135-2.655-3.52-1.29-.32-2.448.27-2.924 1.05-.06.101.055.241.252.178 2.786-.884 2.957 1.674 2.672 2.215a.275.275 0 00-.024.057c.87-.106 1.462.043 1.893.328.447.294.732.738.975 1.231.515 1.042.822 2.335 2.513 2.512v-2.88zm2.406 0c.553-.139 2.074-.563 2.703-1.17.812-.784 1.106-3.135 2.654-3.52 1.29-.32 2.448.27 2.924 1.05.06.101-.055.241-.252.178-2.786-.884-2.957 1.674-2.672 2.215a.27.27 0 01.024.057c-.87-.106-1.462.043-1.893.328-.447.294-.732.738-.975 1.231-.515 1.042-.822 2.335-2.513 2.512v-2.88z" fill="hsla(0,0%,100%,0.6)"></path><path d="M9.753.093a.39.39 0 00-.506 0C8.461.747 6.08 2.946 5.515 3.417a.434.434 0 00-.15.262c-.162.895-.949 4.817-1.12 5.764a.46.46 0 00.067.333c.37.564 1.665 2.752 2.071 3.37a.404.404 0 00.336.187h.768c.19 0 .356-.14.4-.337l.35-1.577a.416.416 0 01.399-.336h1.728c.19 0 .356.139.399.336l.35 1.577a.416.416 0 00.4.337h.768c.133 0 .259-.07.336-.187.406-.618 1.7-2.806 2.07-3.37a.457.457 0 00.067-.333c-.17-.947-.957-4.87-1.118-5.764a.435.435 0 00-.15-.262C12.92 2.946 10.537.747 9.752.093z" fill="url(#activeAghanimScepterGradient)"></path><defs><radialGradient id="activeAghanimScepterGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.03623 10.4684) rotate(-90) scale(9.38905 7.0456)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>` : ""}
1528
- ${item.ability.stat.isGrantedByShard ? `<svg class="shard" viewBox="0 0 19 10" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M0.259504 4.54746C0.272981 4.60325 0.326002 4.64198 0.386194 4.64198C0.831857 4.62418 2.60461 4.45628 3.91732 2.90727C4.49956 2.22054 4.37916 1.21884 3.64777 0.671532C2.91819 0.125197 1.85256 0.238284 1.27032 0.924899C-0.0423919 2.47305 0.17864 4.13525 0.259504 4.54746Z" fill="url(#activeAghanimLeftShardGradient)"></path><path d="M9.46713 9.98081C9.42698 10.0064 9.37572 10.0064 9.33559 9.98081C8.88968 9.67166 6.33212 7.75166 6.33212 4.38581C6.33212 2.96661 7.70742 1.81406 9.40136 1.81406C11.0953 1.81406 12.4706 2.96661 12.4706 4.38581C12.4706 7.75166 9.91303 9.67166 9.46713 9.98081Z" fill="url(#activeAghanimMidShardGradient)"></path><path d="M18.6888 4.54746C18.6753 4.60325 18.6232 4.64198 18.5631 4.64198C18.1173 4.62418 16.3445 4.45628 15.0317 2.90727C14.4494 2.22054 14.5697 1.21884 15.3003 0.671532C16.0308 0.125197 17.0966 0.238284 17.6788 0.924899C18.9917 2.47305 18.7707 4.13525 18.6888 4.54746Z" fill="url(#activeAghanimRightShardGradient)"></path><defs><radialGradient id="activeAghanimMidShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.01787 2.49983) rotate(90) scale(7.50029 5.21143)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimLeftShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.98746 0.625367) rotate(128.66) scale(6.00315 4.79432)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimRightShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(14.2996 0.625367) rotate(51.3402) scale(6.00316 4.7942)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>` : ""}
1529
- <div class="img_stats">
1530
- <img src="${getImageUrl(item.ability.name, "abilities" /* Abilities */)}" alt="" />
1531
- <div class="stats">
1532
- <p class="behavior">技能:${(Array.isArray(dotaconstants3.abilities[item.ability.name].behavior) ? dotaconstants3.abilities[item.ability.name].behavior : [dotaconstants3.abilities[item.ability.name].behavior]).filter((beh) => beh !== "Hidden" || !(item.ability.stat.isGrantedByShard || item.ability.stat.isGrantedByScepter)).map((beh) => behavior[beh]).join("/")}</p>
1533
- ${dotaconstants3.abilities[item.ability.name].target_team ? `<p class="target_team">影响:${(Array.isArray(dotaconstants3.abilities[item.ability.name].target_team) ? dotaconstants3.abilities[item.ability.name].target_team : [dotaconstants3.abilities[item.ability.name].target_team]).map((tt) => target_team[tt]).join("/")}</p>` : ""}
1534
- ${!Array.isArray(dotaconstants3.abilities[item.ability.name].dmg_type) && dotaconstants3.abilities[item.ability.name].dmg_type ? `<p class="dmg_type ${dotaconstants3.abilities[item.ability.name].dmg_type}">伤害类型:</p>` : ""}
1535
- ${dotaconstants3.abilities[item.ability.name].dispellable ? `<p class="dispellable ${dotaconstants3.abilities[item.ability.name].dispellable == "Strong Dispels Only" ? "Strong" : dotaconstants3.abilities[item.ability.name].dispellable}">能否驱散:</p>` : ""}
1536
- ${!Array.isArray(dotaconstants3.abilities[item.ability.name].bkbpierce) && dotaconstants3.abilities[item.ability.name].bkbpierce ? `<p class="bkbpierce">无视减益免疫: ${dotaconstants3.abilities[item.ability.name].bkbpierce == "Yes" ? "是" : "否"}</p>` : ""}
1537
- </div>
1538
- </div>
1539
- ${item.ability.language.description.map((desc) => `<p class="description">${desc}</p>`).join("")}
1540
- ${item.ability.language.aghanimDescription ? `<p class="aghanim_description"><span class="title"><svg viewBox="0 0 19 20" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M4.795 14.99a2.06 2.06 0 00-.96-.388c-1.668-.204-2.506.518-3.107 1.008.464.128.879.364.867.97 2.347-1.605 4.159.84 2.415 2.666-.14.147.65.929.767.718.203-.365.79-1.064 1.445-1.064.964 0 1.529.68 1.823.838.267.144.793-.372.642-.675-.03-.06-.229-.204-.569-.438-1.407-.197-1.935-1.093-2.37-2.026-.276-.593-.503-1.206-.953-1.61zm9.41 0a2.06 2.06 0 01.96-.388c1.668-.204 2.507.518 3.107 1.008-.464.128-.879.364-.867.97-2.347-1.605-4.158.84-2.415 2.666.14.147-.65.929-.768.718-.202-.365-.79-1.064-1.444-1.064-.965 0-1.529.68-1.823.838-.267.144-.793-.372-.642-.675.03-.06.229-.204.569-.438 1.407-.197 1.935-1.093 2.37-2.026.276-.593.503-1.206.953-1.61zm-3.919-2.211c0-.233-.175-.423-.392-.423h-.788c-.217 0-.392.19-.392.423v5.665c0 .232.175.421.392.421h.788c.216 0 .392-.189.392-.421v-5.665zm-1.989 2.543c-.553-.139-2.074-.563-2.702-1.17-.814-.784-1.107-3.135-2.655-3.52-1.29-.32-2.448.27-2.924 1.05-.06.101.055.241.252.178 2.786-.884 2.957 1.674 2.672 2.215a.275.275 0 00-.024.057c.87-.106 1.462.043 1.893.328.447.294.732.738.975 1.231.515 1.042.822 2.335 2.513 2.512v-2.88zm2.406 0c.553-.139 2.074-.563 2.703-1.17.812-.784 1.106-3.135 2.654-3.52 1.29-.32 2.448.27 2.924 1.05.06.101-.055.241-.252.178-2.786-.884-2.957 1.674-2.672 2.215a.27.27 0 01.024.057c-.87-.106-1.462.043-1.893.328-.447.294-.732.738-.975 1.231-.515 1.042-.822 2.335-2.513 2.512v-2.88z" fill="hsla(0,0%,100%,0.6)"></path><path d="M9.753.093a.39.39 0 00-.506 0C8.461.747 6.08 2.946 5.515 3.417a.434.434 0 00-.15.262c-.162.895-.949 4.817-1.12 5.764a.46.46 0 00.067.333c.37.564 1.665 2.752 2.071 3.37a.404.404 0 00.336.187h.768c.19 0 .356-.14.4-.337l.35-1.577a.416.416 0 01.399-.336h1.728c.19 0 .356.139.399.336l.35 1.577a.416.416 0 00.4.337h.768c.133 0 .259-.07.336-.187.406-.618 1.7-2.806 2.07-3.37a.457.457 0 00.067-.333c-.17-.947-.957-4.87-1.118-5.764a.435.435 0 00-.15-.262C12.92 2.946 10.537.747 9.752.093z" fill="url(#activeAghanimScepterGradient)"></path><defs><radialGradient id="activeAghanimScepterGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.03623 10.4684) rotate(-90) scale(9.38905 7.0456)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>
1541
- &nbsp;阿哈利姆神杖</span><span class="desc">${item.ability.language.aghanimDescription}</span></p>` : ""}
1542
- ${item.ability.language.shardDescription ? `<p class="aghanim_description"><span class="title"><svg viewBox="0 0 19 10" fill="hsla(0,0%,100%,0.16)" width="24"><path d="M0.259504 4.54746C0.272981 4.60325 0.326002 4.64198 0.386194 4.64198C0.831857 4.62418 2.60461 4.45628 3.91732 2.90727C4.49956 2.22054 4.37916 1.21884 3.64777 0.671532C2.91819 0.125197 1.85256 0.238284 1.27032 0.924899C-0.0423919 2.47305 0.17864 4.13525 0.259504 4.54746Z" fill="url(#activeAghanimLeftShardGradient)"></path><path d="M9.46713 9.98081C9.42698 10.0064 9.37572 10.0064 9.33559 9.98081C8.88968 9.67166 6.33212 7.75166 6.33212 4.38581C6.33212 2.96661 7.70742 1.81406 9.40136 1.81406C11.0953 1.81406 12.4706 2.96661 12.4706 4.38581C12.4706 7.75166 9.91303 9.67166 9.46713 9.98081Z" fill="url(#activeAghanimMidShardGradient)"></path><path d="M18.6888 4.54746C18.6753 4.60325 18.6232 4.64198 18.5631 4.64198C18.1173 4.62418 16.3445 4.45628 15.0317 2.90727C14.4494 2.22054 14.5697 1.21884 15.3003 0.671532C16.0308 0.125197 17.0966 0.238284 17.6788 0.924899C18.9917 2.47305 18.7707 4.13525 18.6888 4.54746Z" fill="url(#activeAghanimRightShardGradient)"></path><defs><radialGradient id="activeAghanimMidShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.01787 2.49983) rotate(90) scale(7.50029 5.21143)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimLeftShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(3.98746 0.625367) rotate(128.66) scale(6.00315 4.79432)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient><radialGradient id="activeAghanimRightShardGradient" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(14.2996 0.625367) rotate(51.3402) scale(6.00316 4.7942)"><stop stop-color="#00CEFF"></stop><stop offset="1" stop-color="#3443C4"></stop></radialGradient></defs></svg>
1543
- &nbsp;阿哈利姆魔晶</span><span class="desc">${item.ability.language.shardDescription}</span></p>` : ""}
1544
- <div class="notes"${!item.ability.language.notes.length ? ` style="display:none;"` : ""}>
1545
- ${item.ability.language.notes.map((note) => `<p>${note}</p>`).join("")}
1546
- </div>
1547
- <div class="attributes">
1548
- ${item.ability.language.attributes.map((attr) => {
1549
- const parts = attr.split(":");
1550
- return `<p><span class="item">${parts[0]}</span><span class="values">${parts[1]}</span></p>`;
1551
- }).join("")}
1552
- </div>
1553
- <p>
1554
- ${dotaconstants3.abilities[item.ability.name].cd ? `<span class="cooldown"> ${(Array.isArray(dotaconstants3.abilities[item.ability.name].cd) ? dotaconstants3.abilities[item.ability.name].cd : [dotaconstants3.abilities[item.ability.name].cd]).join(
1555
- " / "
1556
- )} </span>` : ""}
1557
- ${dotaconstants3.abilities[item.ability.name].mc ? `<span class="mana_cost"> ${(Array.isArray(dotaconstants3.abilities[item.ability.name].mc) ? dotaconstants3.abilities[item.ability.name].mc : [dotaconstants3.abilities[item.ability.name].mc]).join(
1558
- " / "
1559
- )} </span>` : ""}
1560
- </p>
1561
- <p class="lore"${!item.ability.language.lore ? ` style="display:none;"` : ""}>${item.ability.language.lore}</p>
1562
- </div>
1563
- `
1564
- ).join("")}
1565
- </div>
1566
- <div class="lore">
1567
- ${hero.language.lore}
1568
- </div>
1569
- `;
1570
- $(".wrapper").html(html);
1571
- if (process.env.NODE_ENV === "development")
1572
- import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", $.html());
1573
- return $.html();
1574
- }
1575
- __name(genHeroHTML, "genHeroHTML");
1576
- function genPlayerHTML(player) {
1577
- let $ = cheerio.load(import_fs2.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player.html`, "utf-8"));
1578
- const guildLevel = /* @__PURE__ */ __name((percent) => {
1579
- if (percent <= 25) {
1580
- return "Copper";
1581
- } else if (percent <= 50) {
1582
- return "Silver";
1583
- } else if (percent <= 75) {
1584
- return "Gold";
1585
- } else {
1586
- return "Diamond";
1587
- }
1588
- }, "guildLevel");
1589
- const laneSVG = {
1590
- stomp: `<svg viewBox="0 0 24 24" class="hitagi__sc-1apuy4g-0 hmhZOG"><path d="M8.05731 22.3674L9.60454 22.8002L11.5974 21.6551L12.043 20.0773L13.5902 20.51L15.583 19.3649L16.0287 17.7871L17.5759 18.2199L19.5687 17.0748L20.0143 15.4969L21.5615 15.9297L23.5544 14.7846L24 13.2068L23.4492 12.2014L7.50651 21.3621L8.05731 22.3674ZM12.1328 3.50265L11.0312 1.49196C10.8798 1.21549 10.5316 1.11811 10.2576 1.27556L0.29345 7.00098C0.0194354 7.15843 -0.0808273 7.51346 0.0706444 7.78993L1.44766 10.3033L11.91 4.29159C12.184 4.13414 12.2843 3.77912 12.1328 3.50265ZM18.3935 8.4063L14.1658 9.60458L12.4221 10.6065C12.2851 10.6853 12.111 10.6366 12.0353 10.4983L11.7599 9.99565C11.6842 9.85742 11.7343 9.6799 11.8713 9.60118L13.615 8.59924L13.0642 7.59389L11.3205 8.59584C11.1835 8.67456 11.0094 8.62587 10.9337 8.48765L10.6583 7.98497C10.5826 7.84673 10.6327 7.66922 10.7697 7.5905L12.5134 6.58855L11.9626 5.58321L1.99846 11.3086L6.9557 20.3567L22.8984 11.196L22.2615 10.0336C21.5024 8.64813 19.9073 7.97847 18.3935 8.4063Z"></path></svg>`,
1591
- victory: `<svg viewBox="0 0 512 512"><path d="M198.844 64.75c-.985 0-1.974.03-2.97.094-15.915 1.015-32.046 11.534-37.78 26.937-34.072 91.532-51.085 128.865-61.5 222.876 14.633 13.49 31.63 26.45 50.25 38.125l66.406-196.467 17.688 5.968L163.28 362.5c19.51 10.877 40.43 20.234 62 27.28l75.407-201.53 17.5 6.53-74.937 200.282c19.454 5.096 39.205 8.2 58.78 8.875L381.345 225.5l17.094 7.594-75.875 170.656c21.82-1.237 43.205-5.768 63.437-14.28 43.317-53.844 72.633-109.784 84.5-172.69 5.092-26.992-14.762-53.124-54.22-54.81l-6.155-.282-2.188-5.75c-8.45-22.388-19.75-30.093-31.5-32.47-11.75-2.376-25.267 1.535-35.468 7.376l-13.064 7.47-.906-15c-.99-16.396-10.343-29.597-24.313-35.626-13.97-6.03-33.064-5.232-54.812 9.906l-10.438 7.25-3.812-12.125c-6.517-20.766-20.007-27.985-34.78-27.97zM103.28 188.344C71.143 233.448 47.728 299.56 51.407 359.656c27.54 21.84 54.61 33.693 80.063 35.438 14.155.97 27.94-1.085 41.405-6.438-35.445-17.235-67.36-39.533-92.594-63.53l-3.343-3.157.5-4.595c5.794-54.638 13.946-91.5 25.844-129.03z"/></svg>`,
1592
- fail: `<svg viewBox="0 0 36 36"><path fill="#ff6961" d="M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z"></path><circle fill="#FFF" cx="27" cy="7" r="3"></circle><path fill="#FFF" d="M13.06 13.06l2.367-2.366l3.859 1.158l-2.635 2.847a10.018 10.018 0 0 1 4.392 3.379l5.017-5.017a1.5 1.5 0 0 0-.63-2.497l-9.999-3a1.495 1.495 0 0 0-1.492.376l-3 3a1.5 1.5 0 1 0 2.121 2.12zm16.065 4.949a1.496 1.496 0 0 0-1.262-.503l-6.786.617a9.966 9.966 0 0 1 1.464 2.879l3.548-.322l-1.554 6.995a1.499 1.499 0 1 0 2.928.65l2-9a1.5 1.5 0 0 0-.338-1.316zM13 16a8 8 0 1 0 0 16a8 8 0 0 0 0-16zm0 14a6 6 0 1 1 .002-12.002A6 6 0 0 1 13 30z"></path></svg>`,
1593
- stomped: `<svg viewBox="-1 0 19 19"><path d="M16.417 9.579A7.917 7.917 0 1 1 8.5 1.662a7.917 7.917 0 0 1 7.917 7.917zm-2.458 2.96a.396.396 0 0 0-.396-.397h-.667a1.527 1.527 0 0 0-1.249-1.114.777.777 0 0 0 .014-.145V9.378a.794.794 0 0 0-.792-.792H8.201a2.984 2.984 0 0 0-1.682-.516l-.11.002V7.42h2.997a.396.396 0 1 0 0-.792H6.41v-1.3a.396.396 0 0 0-.396-.397H4.891a.396.396 0 0 0 0 .792h.727V8.21a2.997 2.997 0 1 0 3.836 3.466h.71a1.526 1.526 0 1 0 2.732 1.26h.667a.396.396 0 0 0 .396-.397zM8.078 9.507a2.205 2.205 0 1 1-1.559-.646 2.19 2.19 0 0 1 1.559.646zm4.078 3.03a.734.734 0 1 1-.733-.734.735.735 0 0 1 .733.733z"/></svg>`,
1594
- tie: `<svg fill="#fff" viewBox="0 0 512.001 512.001"><g><g><path d="M120.988,239.868c-4.496,10.625-5.122,20.183-5.157,20.811c-0.267,4.607,3.243,8.547,7.849,8.829 c4.618,0.29,8.574-3.228,8.873-7.833c0.265-4.771,2.339-13.092,5.884-19.44C137.421,242.113,141.397,242.649,120.988,239.868z"/></g></g><g><g><path d="M391.178,255.418c-0.211,8.054-2.458,17.62-6.74,28.398c-1.708,4.299,0.393,9.168,4.692,10.875 c4.293,1.708,9.167-0.39,10.875-4.692c5.103-12.842,7.74-24.392,7.943-34.581H391.178z"/></g></g><g><g><path d="M164.769,210.51c1.046,3.339,1.397,6.953,0.893,10.65c-0.293,2.146-0.857,4.188-1.648,6.1c0,0,51.266,3.416,198.065,3.949 c-0.086-6.331,2.19-12.199,6.244-16.732C217.627,214.046,164.769,210.51,164.769,210.51z"/></g></g><g><g><circle cx="37.179" cy="128.669" r="29.491"/></g></g><g><g><path d="M510.146,391.511l-37.916-66.985c14.35-49.173,20.678-68.137,20.678-68.137l8.949-67.014 c1.502-10.977-6.248-21.075-17.235-22.468l-18.183-2.305c-10.984-1.393-20.996,6.445-22.293,17.431l-1.884,15.955l28.718-21.317 l-37.91,42.278h-46.432c-6.571,0-11.898,5.328-11.898,11.898c0,6.57,5.328,11.898,11.898,11.898h51.744 c3.381,0,6.601-1.438,8.859-3.956l41.456-46.234l-32.023,54.694c-5.28,9.018-14.374,8.169-18.293,8.167c-1.959,0-3.31,0-5.295,0 c-0.399,0.898,3.152-7.399-24.44,57.181c-0.548,1.284-0.907,2.642-1.06,4.031l-8.934,80.338 c-0.939,8.447,5.667,15.857,14.208,15.857c7.179,0,13.361-5.401,14.172-12.701l8.702-78.244l21.512-50.353l-14.121,50.463 c-1.158,3.756-0.718,7.823,1.218,11.243l40.949,72.345c3.885,6.864,12.596,9.276,19.459,5.392 C511.615,407.085,514.03,398.373,510.146,391.511z"/></g></g><g><g><circle cx="464.865" cy="128.702" r="29.491"/></g></g><g><g><path d="M142.923,206.051l-59.556-8.118l-39.135-18.451l13.626,2.292c-1.422-10.945-11.411-18.577-22.254-17.202l-18.182,2.305 C6.43,168.271-1.315,178.374,0.186,189.345l9.12,68.689l21.865,70.857l5.829,70.795c0.646,7.848,7.527,13.705,15.401,13.057 c7.859-0.647,13.705-7.542,13.058-15.401l-5.956-72.345c-0.084-1.031-0.281-2.05-0.585-3.039l-14.123-50.463l21.514,50.353 l8.702,78.244c0.873,7.86,7.96,13.486,15.768,12.612c7.838-0.871,13.483-7.931,12.612-15.768l-8.934-80.338 c-0.154-1.388-0.511-2.747-1.06-4.032l-27.336-61.43l-2.945-24.951l-29.029-25.179l40.79,19.231 c1.097,0.517,2.266,0.862,3.468,1.027l61.369,8.365c6.521,0.887,12.509-3.68,13.396-10.183 C153.994,212.936,149.435,206.939,142.923,206.051z"/></g></g></svg>`
1595
- };
1596
- const outcomeCounts = {
1597
- victory: 0,
1598
- stomp: 0,
1599
- fail: 0,
1600
- stomped: 0,
1601
- tie: 0
1602
- };
1603
- const processLaneOutcome = /* @__PURE__ */ __name((outcome) => {
1604
- switch (outcome) {
1605
- case "RADIANT_VICTORY":
1606
- return { radiant: "victory", dire: "fail" };
1607
- case "RADIANT_STOMP":
1608
- return { radiant: "stomp", dire: "stomped" };
1609
- case "DIRE_VICTORY":
1610
- return { radiant: "fail", dire: "victory" };
1611
- case "DIRE_STOMP":
1612
- return { radiant: "stomped", dire: "stomp" };
1613
- default:
1614
- return { radiant: "tie", dire: "tie" };
1615
- }
1616
- }, "processLaneOutcome");
1617
- let nearMatchCount = 25, nearWinCount = 0, streak = 0;
1618
- player.matches.forEach((match) => {
1619
- const innerPlayer = match.players[0];
1620
- nearWinCount += match.didRadiantWin == innerPlayer.isRadiant ? 1 : 0;
1621
- const didWin = match.didRadiantWin === innerPlayer.isRadiant;
1622
- if (!player.streak) {
1623
- if (streak != 0) {
1624
- if (didWin && streak > 0)
1625
- streak++;
1626
- else if (!didWin && streak < 0)
1627
- streak--;
1628
- else
1629
- player.streak = streak;
1630
- } else
1631
- streak = didWin ? 1 : -1;
1632
- }
1633
- const laneResult = {
1634
- top: processLaneOutcome(match.topLaneOutcome),
1635
- mid: processLaneOutcome(match.midLaneOutcome),
1636
- bottom: processLaneOutcome(match.bottomLaneOutcome)
1637
- };
1638
- let laneKey = "mid";
1639
- if (innerPlayer.lane === "SAFE_LANE") {
1640
- laneKey = innerPlayer.isRadiant ? "bottom" : "top";
1641
- } else if (innerPlayer.lane === "OFF_LANE") {
1642
- laneKey = innerPlayer.isRadiant ? "top" : "bottom";
1643
- }
1644
- match.laneResult = laneResult[laneKey][innerPlayer.isRadiant ? "radiant" : "dire"];
1645
- if (match.laneResult in outcomeCounts) {
1646
- outcomeCounts[match.laneResult]++;
1647
- }
1648
- });
1649
- const playerHTML = `
1650
- <div class="avatar"><img src="${player.steamAccount.avatar}" alt="" /></div>
1651
- <div class="info">
1652
- <p class="name">${player.steamAccount.name}${player.guildMember ? ` <span class="guild ${guildLevel(player.guildMember.guild.currentPercentile)}">[${player.guildMember.guild.tag}]</span></p>` : ""}
1653
- <p class="matches"><span>场次:${player.matchCount}(<span class="win">${player.winCount}</span>/<span class="lose">${player.matchCount - player.winCount}</span>)</span>胜率:<span style="color:${winRateColor(
1654
- player.winCount / player.matchCount
1655
- )};">${(player.winCount / player.matchCount * 100).toFixed(2)}%</span></p>
1656
- <p class="matches"><span>最近25场:<span class="win">${nearWinCount}</span>/<span class="lose">${nearMatchCount - nearWinCount}</span></span><span>胜率:<span style="color:${winRateColor(nearWinCount / nearMatchCount)};">${(nearWinCount / nearMatchCount * 100).toFixed(2)}%</span></span><span>评分:${player.performance.imp}</span></span></p>
1657
- <p class="matches"><span>对线:<span class="victory">${outcomeCounts.victory + outcomeCounts.stomp}(<span class="stomp">${outcomeCounts.stomp}</span>)</span>-<span class="tie">${outcomeCounts.tie}</span>-<span class="fail">${outcomeCounts.fail + outcomeCounts.stomped}(<span class="stomped">${outcomeCounts.stomped}</span>)</span></span><span>线优:<span style="color:${winRateColor(
1658
- (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie / 2) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.tie + outcomeCounts.fail + outcomeCounts.stomped)
1659
- )};">${((outcomeCounts.victory + outcomeCounts.stomp) / (outcomeCounts.victory + outcomeCounts.stomp + outcomeCounts.fail + outcomeCounts.stomped) * 100).toFixed(2)}%</span></span></p>
1660
- </div>
1661
- <div class="rank">
1662
- <img class="medal" src="${getImageUrl(
1663
- "medal_" + ((player.steamAccount.seasonLeaderboardRank ? player.steamAccount.seasonLeaderboardRank <= 100 ? player.steamAccount.seasonLeaderboardRank <= 10 ? "8c" : "8b" : player.steamAccount.seasonRank?.toString().split("")[0] : player.steamAccount.seasonRank?.toString().split("")[0]) ?? "0")
1664
- )}" alt="" />
1665
- <img class="star" src="${getImageUrl("star_" + (player.steamAccount.seasonRank?.toString().split("")[1] ?? "0"))}" alt="" />
1666
- <p>${player.steamAccount.seasonLeaderboardRank ?? ""}</p>
1667
- </div>`;
1668
- const heroesCountPixels = 800 - ($(".tip:not(.row):not(.win_count):not(.lose_count)").length + 1) * 40;
1669
- const highestCountsTotal = {
1670
- winCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.winCount)),
1671
- loseCount: Math.max(...player.heroesPerformanceTop10.map((hero) => hero.matchCount - hero.winCount))
1672
- };
1673
- const pixelOfPerMatchInTotal = heroesCountPixels / (highestCountsTotal.winCount + highestCountsTotal.loseCount);
1674
- const highestCountsNear = {
1675
- winCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.winCount)),
1676
- loseCount: Math.max(...player.heroesPerformance?.filter((hero) => hero.matchCount > 1)?.map((hero) => hero.matchCount - hero.winCount))
1677
- };
1678
- const nearAdjustmentFactor = Math.min(highestCountsTotal.winCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount), highestCountsTotal.loseCount / (highestCountsTotal.winCount + highestCountsTotal.loseCount));
1679
- const pixelOfPerMatchInNear = heroesCountPixels / (highestCountsNear?.winCount + highestCountsNear?.loseCount) * nearAdjustmentFactor;
1680
- const heroesTotalHTML = player.heroesPerformanceTop10.map(
1681
- (hero) => `
1682
- <span><img alt="" src="${getImageUrl(hero.hero.shortName, "heroes/icons" /* HeroIcons */)}" /></span>
1683
- <span class="count">${hero.matchCount}</span>
1684
- <span class="win_rate">${(hero.winCount / hero.matchCount * 100).toFixed(0)}%</span>
1685
- <span class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
1686
- <span class="win" style="${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInTotal}px">${hero.winCount}</span>
1687
- <span class="lose" style="${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInTotal}px">${hero.matchCount - hero.winCount}</span>`
1688
- ).join("") + player.heroesPerformance.filter((hero) => hero.matchCount > 1).map(
1689
- (hero, index) => `
1690
- <span style="order:${index + 1};"><img alt="" src="${getImageUrl(hero.hero.shortName, "heroes/icons" /* HeroIcons */)}" /></span>
1691
- <span style="order:${index + 1};" class="count">${hero.matchCount}</span>
1692
- <span style="order:${index + 1};" class="win_rate">${(hero.winCount / hero.matchCount * 100).toFixed(0)}%</span>
1693
- <span style="order:${index + 1};" class="imp">${(hero.imp > 0 ? "+" : "") + hero.imp}</span>
1694
- <span class="win" style="order:${index + 1};${hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${hero.winCount * pixelOfPerMatchInNear}px">${hero.winCount}</span>
1695
- <span class="lose" style="order:${index + 1};${hero.matchCount - hero.winCount == 0 ? "visibility:hidden;" : ""}width: ${(hero.matchCount - hero.winCount) * pixelOfPerMatchInNear}px">${hero.matchCount - hero.winCount}</span>`
1696
- ).join("");
1697
- const streakHTML = `<div class="streak" style="box-shadow:none;color:${winRateColor((player.streak + 10) / 20)};">${Math.abs(player.streak) + (player.streak > 0 ? "连胜" : "连败")}</div>`;
1698
- const matchesHTML = player.matches.map(
1699
- (match) => `
1700
- <tr class="match ${match.didRadiantWin == match.players[0].isRadiant ? "win" : "lose"}">
1701
- <td>${match.id}</td>
1702
- <td>
1703
- <p>${lobbyTypes[match.lobbyType] || match.lobbyType}</p>
1704
- <p>${gameMode[match.gameMode] || match.gameMode}</p>
1705
- </td>
1706
- <td><img alt="" src="${getImageUrl(match.players[0].hero.shortName, "heroes/icons" /* HeroIcons */)}" /></td>
1707
- <td style="line-height: 20px">
1708
- <p>${((match.players[0].kills + match.players[0].assists) / Math.max(1, match.players[0].deaths)).toFixed(2)} (${((match.players[0].kills + match.players[0].assists) / (match.players[0].isRadiant ? match.radiantKills.reduce((acc, cva) => acc + cva, 0) : match.direKills.reduce((acc, cva) => acc + cva, 0)) * 100).toFixed(0)}%)</p>
1709
- <p>${match.players[0].kills}/${match.players[0].deaths}/${match.players[0].assists}</p>
1710
- </td>
1711
- <td>
1712
- <div class="player_lane ${match.laneResult}">${laneSVG[match.laneResult]}</div>
1713
- </td>
1714
- <td style="line-height: 20px">${(0, import_moment.default)(new Date(match.endDateTime * 1e3)).format("YYYY-MM-DD HH:mm:ss").slice(2)}</td>
1715
- <td>${sec2time(match.durationSeconds)}</td>
1716
- <td>${(match.players[0].imp > 0 ? "+" : "") + match.players[0].imp}</td>
1717
- <td><img class="medal" src="${getImageUrl("medal_" + match.rank.toString().split("")[0])}" style="width: 100%" /></td>
1718
- </tr>`
1719
- ).join("");
1720
- const dotaPlusHTML = player.dotaPlus.map(
1721
- (hero) => `
1722
- <div class="hero">
1723
- <img src="${getImageUrl(hero.shortName, "heroes" /* Heroes */)}" alt="" />
1724
- <div class="level"><img src="${getImageUrl("hero_badge_" + Math.ceil((hero.level + 1) / 6))}" alt="" /><span>${hero.level}</span></div>
1725
- <span>${(hero.winCount / hero.matchCount * 100).toFixed(2)}%</span>
1726
- <span>${hero.matchCount}</span>
1727
- </div>`
1728
- ).join("");
1729
- $(".player").html(playerHTML);
1730
- $(".heroes > span:not(.tip)").remove();
1731
- $(".heroes .tip.near").before(heroesTotalHTML);
1732
- if (player.streak > 1 || player.streak < -1)
1733
- $(".streak").replaceWith(streakHTML);
1734
- $(".matches tbody").html(matchesHTML);
1735
- $(".plus").html(dotaPlusHTML);
1736
- if (process.env.NODE_ENV === "development")
1737
- import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", $.html());
1738
- return $.html();
1739
- }
1740
- __name(genPlayerHTML, "genPlayerHTML");
1741
- async function playerIsInvalid(steamAccountId) {
1742
- try {
1743
- let queryRes = await query(VERIFYING_PLAYER(steamAccountId));
1744
- if (queryRes.status == 200) {
1745
- if (queryRes.data.data.player.matchCount != null)
1746
- return { isInvalid: true };
1747
- else
1748
- return { isInvalid: false, reason: "SteamID无效或无任何场次。" };
1749
- }
1750
- } catch (error) {
1751
- console.error(error);
1752
- return { isInvalid: false, reason: "网络状况不佳SteamID验证失败,请稍后重试。" };
1753
- }
1754
- }
1755
- __name(playerIsInvalid, "playerIsInvalid");
1756
- function sec2time(sec) {
1757
- return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
1758
- }
1759
- __name(sec2time, "sec2time");
1760
- function winRateColor(value) {
1761
- value = value * 100;
1762
- value = Math.max(0, Math.min(100, value));
1763
- let red, green, blue;
1764
- if (value <= 50) {
1765
- let scale = Math.round(255 * (value / 50));
1766
- red = 255;
1767
- green = scale;
1768
- blue = scale;
1769
- } else {
1770
- let scale = Math.round(255 * ((value - 50) / 50));
1771
- red = 255 - scale;
1772
- green = 255;
1773
- blue = 255 - scale;
1774
- }
1775
- const toHex = /* @__PURE__ */ __name((color) => color.toString(16).padStart(2, "0").toUpperCase(), "toHex");
1776
- return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
1777
- }
1778
- __name(winRateColor, "winRateColor");
1779
- function formatNumber(num) {
1780
- return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1781
- }
1782
- __name(formatNumber, "formatNumber");
1783
- function readDirectoryFilesSync(directoryPath) {
1784
- try {
1785
- const files = import_fs2.default.readdirSync(directoryPath);
1786
- const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
1787
- return fileNames;
1788
- } catch (error) {
1789
- console.error("Error reading directory:", error);
1790
- return [];
1791
- }
1792
- }
1793
- __name(readDirectoryFilesSync, "readDirectoryFilesSync");
1485
+ __name(genImageHTML, "genImageHTML");
1794
1486
  // Annotate the CommonJS export names for ESM import in node:
1795
1487
  0 && (module.exports = {
1796
1488
  Config,