@sjtdev/koishi-plugin-dota2tracker 1.1.0 → 1.1.2-beta.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
@@ -44,13 +44,413 @@ 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"));
58
+ var dotaconstants2 = __toESM(require("dotaconstants"));
59
+ var import_path = __toESM(require("path"));
60
+
61
+ // src/queries.ts
53
62
  var dotaconstants = __toESM(require("dotaconstants"));
63
+ function MATCH_INFO(matchId) {
64
+ return `
65
+ {
66
+ match(id: ${matchId}) {
67
+ id
68
+ didRadiantWin
69
+ lobbyType
70
+ gameMode
71
+ regionId
72
+ parsedDateTime
73
+ startDateTime
74
+ endDateTime
75
+ actualRank
76
+ rank
77
+ averageRank
78
+ durationSeconds
79
+ topLaneOutcome
80
+ midLaneOutcome
81
+ bottomLaneOutcome
82
+ radiantKills
83
+ direKills
84
+ players {
85
+ steamAccountId
86
+ steamAccount {
87
+ name
88
+ }
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
+ startDateTime
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 PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD(steamAccountIds) {
306
+ return `{
307
+ players(steamAccountId: [${steamAccountIds.join()}]) {
308
+ steamAccount {
309
+ id
310
+ avatar
311
+ name
312
+ seasonRank
313
+ }
314
+ matches(request: {take: 10}) {
315
+ didRadiantWin
316
+ startDateTime
317
+ players {
318
+ isRadiant
319
+ kills
320
+ deaths
321
+ assists
322
+ steamAccount {
323
+ id
324
+ }
325
+ hero {
326
+ shortName
327
+ }
328
+ imp
329
+ }
330
+ }
331
+ }
332
+ }
333
+ `;
334
+ }
335
+ __name(PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD, "PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD");
336
+ function CURRENT_GAMEVERSION() {
337
+ return `
338
+ {
339
+ constants {
340
+ gameVersions{name id}
341
+ }
342
+ }
343
+
344
+ `;
345
+ }
346
+ __name(CURRENT_GAMEVERSION, "CURRENT_GAMEVERSION");
347
+ function ALL_ABILITIES_CHINESE_NAME() {
348
+ return `
349
+ {
350
+ constants {
351
+ abilities(language:S_CHINESE){
352
+ id
353
+ language{displayName}
354
+ }
355
+ gameVersions{name id}
356
+ }
357
+ }
358
+
359
+ `;
360
+ }
361
+ __name(ALL_ABILITIES_CHINESE_NAME, "ALL_ABILITIES_CHINESE_NAME");
362
+ function HERO_INFO(heroId) {
363
+ return `
364
+ {
365
+ constants {
366
+ hero(id: ${heroId}, language: S_CHINESE) {
367
+ id
368
+ name
369
+ shortName
370
+ aliases
371
+ roles {
372
+ roleId
373
+ level
374
+ }
375
+ language {
376
+ displayName
377
+ lore
378
+ hype
379
+ }
380
+ abilities {
381
+ ability(language: S_CHINESE) {
382
+ name
383
+ language {
384
+ displayName
385
+ description
386
+ attributes
387
+ lore
388
+ aghanimDescription
389
+ shardDescription
390
+ notes
391
+ }
392
+ stat {
393
+ type
394
+ behavior
395
+ unitTargetType
396
+ unitTargetTeam
397
+ unitTargetFlags
398
+ unitDamageType
399
+ cooldown
400
+ manaCost
401
+ spellImmunity
402
+ isOnCastbar
403
+ isGrantedByShard
404
+ isGrantedByScepter
405
+ hasShardUpgrade
406
+ hasScepterUpgrade
407
+ }
408
+ }
409
+ }
410
+ talents {
411
+ abilityId
412
+ slot
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ `;
419
+ }
420
+ __name(HERO_INFO, "HERO_INFO");
421
+ function HERO_MATCHUP_WINRATE(heroId) {
422
+ return `
423
+ {
424
+ heroStats {
425
+ matchUp(heroId: ${heroId}, take: ${Object.keys(dotaconstants.heroes).length - 1},bracketBasicIds:LEGEND_ANCIENT) {
426
+ heroId
427
+ matchCountWith
428
+ matchCountVs
429
+ with {
430
+ heroId1
431
+ winRateHeroId1
432
+ heroId2
433
+ winRateHeroId2
434
+ winCount
435
+ matchCount
436
+ }
437
+ vs {
438
+ heroId1
439
+ winRateHeroId1
440
+ heroId2
441
+ winRateHeroId2
442
+ winCount
443
+ matchCount
444
+ }
445
+ }
446
+ }
447
+ }
448
+
449
+ `;
450
+ }
451
+ __name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
452
+
453
+ // src/utils.ts
54
454
  var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
55
455
  async function query(query_str) {
56
456
  return await import_axios.default.post(CONFIGS.STRATZ_API.URL, query_str, {
@@ -182,8 +582,8 @@ function getFormattedMatchData(match) {
182
582
  const itemId = player[key];
183
583
  if (itemId === void 0 || itemId === null) {
184
584
  player.items.push(null);
185
- } else if (dotaconstants.item_ids[itemId]) {
186
- const name2 = dotaconstants.item_ids[itemId];
585
+ } else if (dotaconstants2.item_ids[itemId]) {
586
+ const name2 = dotaconstants2.item_ids[itemId];
187
587
  const isRecipe = name2.startsWith(prefix);
188
588
  const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
189
589
  player.items.push({
@@ -201,8 +601,8 @@ function getFormattedMatchData(match) {
201
601
  const itemId = player[key];
202
602
  if (itemId === void 0 || itemId === null) {
203
603
  player.backpacks.push(null);
204
- } else if (dotaconstants.item_ids[itemId]) {
205
- const name2 = dotaconstants.item_ids[itemId];
604
+ } else if (dotaconstants2.item_ids[itemId]) {
605
+ const name2 = dotaconstants2.item_ids[itemId];
206
606
  const isRecipe = name2.startsWith(prefix);
207
607
  const cleanName = isRecipe ? name2.substring(prefix.length) : name2;
208
608
  player.backpacks.push({
@@ -224,8 +624,8 @@ function getFormattedMatchData(match) {
224
624
  const itemId = player.additionalUnit[key];
225
625
  if (itemId === void 0 || itemId === null) {
226
626
  player.unitItems.push(null);
227
- } else if (dotaconstants.item_ids[itemId]) {
228
- const name2 = dotaconstants.item_ids[itemId];
627
+ } else if (dotaconstants2.item_ids[itemId]) {
628
+ const name2 = dotaconstants2.item_ids[itemId];
229
629
  const isRecipe = name2.startsWith(prefix2);
230
630
  const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
231
631
  player.unitItems.push({
@@ -243,8 +643,8 @@ function getFormattedMatchData(match) {
243
643
  const itemId = player.additionalUnit[key];
244
644
  if (itemId === void 0 || itemId === null) {
245
645
  player.unitBackpacks.push(null);
246
- } else if (dotaconstants.item_ids[itemId]) {
247
- const name2 = dotaconstants.item_ids[itemId];
646
+ } else if (dotaconstants2.item_ids[itemId]) {
647
+ const name2 = dotaconstants2.item_ids[itemId];
248
648
  const isRecipe = name2.startsWith(prefix2);
249
649
  const cleanName = isRecipe ? name2.substring(prefix2.length) : name2;
250
650
  player.unitBackpacks.push({
@@ -309,381 +709,74 @@ function getFormattedMatchData(match) {
309
709
  } else if (currentContribution === lowestContribution) {
310
710
  const currentPlayerScore = player.kills + player.assists;
311
711
  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");
323
-
324
- // src/queries.ts
325
- var dotaconstants2 = __toESM(require("dotaconstants"));
326
- function MATCH_INFO(matchId) {
327
- return `
328
- {
329
- match(id: ${matchId}) {
330
- id
331
- didRadiantWin
332
- lobbyType
333
- gameMode
334
- regionId
335
- parsedDateTime
336
- startDateTime
337
- endDateTime
338
- actualRank
339
- rank
340
- averageRank
341
- durationSeconds
342
- topLaneOutcome
343
- midLaneOutcome
344
- bottomLaneOutcome
345
- radiantKills
346
- direKills
347
- players {
348
- steamAccountId
349
- steamAccount {
350
- name
351
- }
352
- level
353
- hero {
354
- id
355
- name
356
- 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
390
- }
391
- }
392
- playbackData {
393
- purchaseEvents {
394
- itemId
395
- time
396
- }
397
- }
398
- heroDamage
399
- towerDamage
400
- stats {
401
- heroDamageReport {
402
- receivedTotal {
403
- physicalDamage
404
- magicalDamage
405
- pureDamage
406
- }
407
- }
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
- }
426
- }
427
- }
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
- }
443
- pickBans {
444
- isPick
445
- bannedHeroId
446
- heroId
447
- order
448
- }
449
- }
450
- }
451
-
452
- `;
453
- }
454
- __name(MATCH_INFO, "MATCH_INFO");
455
- function VERIFYING_PLAYER(steamAccountId) {
456
- return `
457
- {
458
- player(steamAccountId: ${steamAccountId}) {
459
- matchCount
460
- }
461
- }
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
- }
476
- }
477
- }
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
- }
562
- }
712
+ if (currentPlayerScore < lowestPlayerScore) {
713
+ return player;
714
+ } else if (currentPlayerScore === lowestPlayerScore) {
715
+ return player.heroDamage < lowest.heroDamage ? player : lowest;
563
716
  }
564
- `;
717
+ }
718
+ return lowest;
719
+ }).titles.push({ name: "摸", color: "#DDDDDD" });
720
+ return match;
565
721
  }
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
- `;
722
+ __name(getFormattedMatchData, "getFormattedMatchData");
723
+ function sec2time(sec) {
724
+ return sec ? (sec < 0 ? "-" : "") + Math.floor(Math.abs(sec) / 60) + ":" + ("00" + Math.abs(sec) % 60).slice(-2) : "--:--";
576
725
  }
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
- `;
726
+ __name(sec2time, "sec2time");
727
+ function formatNumber(num) {
728
+ return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
591
729
  }
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
- `;
730
+ __name(formatNumber, "formatNumber");
731
+ function readDirectoryFilesSync(directoryPath) {
732
+ try {
733
+ const files = import_fs.default.readdirSync(directoryPath);
734
+ const fileNames = files.map((file) => import_path.default.basename(file, import_path.default.extname(file)));
735
+ return fileNames;
736
+ } catch (error) {
737
+ console.error("Error reading directory:", error);
738
+ return [];
739
+ }
650
740
  }
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
- `;
741
+ __name(readDirectoryFilesSync, "readDirectoryFilesSync");
742
+ function winRateColor(value) {
743
+ value = value * 100;
744
+ value = Math.max(0, Math.min(100, value));
745
+ let red, green, blue;
746
+ if (value <= 50) {
747
+ let scale = Math.round(255 * (value / 50));
748
+ red = 255;
749
+ green = scale;
750
+ blue = scale;
751
+ } else {
752
+ let scale = Math.round(255 * ((value - 50) / 50));
753
+ red = 255 - scale;
754
+ green = 255;
755
+ blue = 255 - scale;
756
+ }
757
+ const toHex = /* @__PURE__ */ __name((color) => color.toString(16).padStart(2, "0").toUpperCase(), "toHex");
758
+ return `#${toHex(red)}${toHex(green)}${toHex(blue)}`;
681
759
  }
682
- __name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
760
+ __name(winRateColor, "winRateColor");
761
+ async function playerisValid(steamAccountId) {
762
+ try {
763
+ let queryRes = await query(VERIFYING_PLAYER(steamAccountId));
764
+ if (queryRes.status == 200) {
765
+ if (queryRes.data.data.player.matchCount != null)
766
+ return { isValid: true };
767
+ else
768
+ return { isValid: false, reason: "SteamID无效或无任何场次。" };
769
+ }
770
+ } catch (error) {
771
+ console.error(error);
772
+ return { isValid: false, reason: "网络状况不佳SteamID验证失败,请稍后重试。" };
773
+ }
774
+ }
775
+ __name(playerisValid, "playerisValid");
683
776
 
684
777
  // src/index.ts
685
778
  var import_fs2 = __toESM(require("fs"));
686
- var cheerio = __toESM(require("cheerio"));
779
+ var import_path2 = __toESM(require("path"));
687
780
  var import_moment = __toESM(require("moment"));
688
781
  var dotaconstants3 = __toESM(require("dotaconstants"));
689
782
 
@@ -956,14 +1049,19 @@ var dotaconstants_add_default = {
956
1049
  // src/index.ts
957
1050
  var import_koishi2 = require("koishi");
958
1051
  var ejs = __toESM(require("ejs"));
959
- var import_path = __toESM(require("path"));
960
1052
  var name = "dota2tracker";
961
1053
  var usage = "DOTA2Bot插件-提供自动追踪群友的最新对局的功能(需群友绑定),以及一系列查询功能。";
962
1054
  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
- });
1055
+ var Config = import_koishi.Schema.intersect([
1056
+ import_koishi.Schema.object({
1057
+ STRATZ_API_TOKEN: import_koishi.Schema.string().required().description("※必须。stratz.com的API TOKEN,可在 https://stratz.com/api 获取")
1058
+ }).description("基础设置"),
1059
+ import_koishi.Schema.object({
1060
+ 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 有模板展示。"),
1061
+ template_player: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/player`)]).default("player_1").description("生成玩家信息图片使用的模板。(目前仅有一张模板)"),
1062
+ template_hero: import_koishi.Schema.union([...readDirectoryFilesSync(`./node_modules/@sjtdev/koishi-plugin-${name}/template/hero`)]).default("hero_1").description("生成英雄信息图片使用的模板。(目前仅有一张模板)")
1063
+ }).description("模板设置")
1064
+ ]);
967
1065
  var pendingMatches = [];
968
1066
  var random = new import_koishi2.Random(() => Math.random());
969
1067
  async function apply(ctx, config) {
@@ -1008,11 +1106,15 @@ async function apply(ctx, config) {
1008
1106
  );
1009
1107
  return;
1010
1108
  }
1011
- let verifyRes = await playerIsInvalid(steam_id);
1012
- if (!verifyRes.isInvalid) {
1109
+ let verifyRes = await playerisValid(steam_id);
1110
+ if (!verifyRes.isValid) {
1013
1111
  session.send(`绑定失败,${verifyRes.reason}`);
1014
1112
  return;
1015
1113
  }
1114
+ if (!/^(?:.{1,20})?$/.test(nick_name ?? "")) {
1115
+ session.send("别名过长,请限制在20个字符以内。(也可以留空)");
1116
+ return;
1117
+ }
1016
1118
  session.send(
1017
1119
  `
1018
1120
  绑定成功,
@@ -1041,6 +1143,10 @@ async function apply(ctx, config) {
1041
1143
  session.send("请输入你的别名。");
1042
1144
  return;
1043
1145
  }
1146
+ if (!/^.{1,20}$/.test(nick_name ?? "")) {
1147
+ session.send("别名过长,请限制在20个字符以内。");
1148
+ return;
1149
+ }
1044
1150
  sessionPlayer.nickName = nick_name;
1045
1151
  await ctx.database.set("dt_subscribed_players", sessionPlayer.id, { nickName: sessionPlayer.nickName });
1046
1152
  session.send(`改名成功,现在你叫${nick_name}了。`);
@@ -1051,8 +1157,30 @@ async function apply(ctx, config) {
1051
1157
  });
1052
1158
  ctx.command("查询群友", "查询本群已绑定的玩家").action(async ({ session }) => {
1053
1159
  if (session.guild) {
1054
- let queryRes = await ctx.database.get("dt_subscribed_players", { guildId: session.event.guild.id });
1055
- session.send("开发中,未来此功能会重写。\n" + queryRes.map((item) => `${item.nickName ?? ""},ID:${item.userId},SteamID:${item.steamId}`).join("\n"));
1160
+ const subscribedPlayers = await ctx.database.get("dt_subscribed_players", { guildId: session.event.guild.id, platform: session.platform });
1161
+ if (!subscribedPlayers.length) {
1162
+ session.send("本群尚无绑定玩家。");
1163
+ return;
1164
+ }
1165
+ if (subscribedPlayers.length <= 20) {
1166
+ try {
1167
+ const memberList = await session.bot.getGuildMemberList(session.event.guild.id);
1168
+ ctx.logger.info(JSON.stringify(memberList.data));
1169
+ let queryRes = await query(PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD(subscribedPlayers.map((player) => player.steamId)));
1170
+ if (queryRes.status == 200) {
1171
+ const users = subscribedPlayers.map((subscribedPlayer) => {
1172
+ const queryPlayer = queryRes.data.data.players.find((player) => player.steamAccount.id == subscribedPlayer.steamId);
1173
+ const queryMember = memberList.data.find((member) => member.user.id == subscribedPlayer.userId);
1174
+ return { ...subscribedPlayer, ...queryPlayer, ...queryMember };
1175
+ });
1176
+ session.send(await ctx.puppeteer.render(genImageHTML(users, "guild_member" /* GuildMember */, "guild_member" /* GuildMember */)));
1177
+ } else
1178
+ throw 0;
1179
+ } catch (error) {
1180
+ console.error(error);
1181
+ session.send("查询群友失败。");
1182
+ }
1183
+ }
1056
1184
  }
1057
1185
  });
1058
1186
  async function queryAndDisplayMatch(session, matchId) {
@@ -1069,7 +1197,7 @@ async function apply(ctx, config) {
1069
1197
  }
1070
1198
  }
1071
1199
  if (match && match.parsedDateTime) {
1072
- session.send(await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match)));
1200
+ session.send(await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */)));
1073
1201
  ctx.database.upsert("dt_previous_query_results", (row) => [{ matchId: match.id, data: match, queryTime: /* @__PURE__ */ new Date() }]);
1074
1202
  } else {
1075
1203
  pendingMatches.push({ matchId, platform: session.event.platform, guildId: session.event.guild.id });
@@ -1175,7 +1303,7 @@ async function apply(ctx, config) {
1175
1303
  player.heroesPerformanceTop10 = playerExtra.heroesPerformance.slice(0, 10);
1176
1304
  } else
1177
1305
  throw 0;
1178
- session.send(await ctx.puppeteer.render(genPlayerHTML(player)));
1306
+ session.send(await ctx.puppeteer.render(genImageHTML(player, config.template_player, "player" /* Player */)));
1179
1307
  } catch (error) {
1180
1308
  console.error(error);
1181
1309
  session.send("获取玩家信息失败。");
@@ -1228,7 +1356,7 @@ async function apply(ctx, config) {
1228
1356
  if (queryRes3.status == 200) {
1229
1357
  let hero = queryRes3.data.data.constants.hero;
1230
1358
  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)));
1359
+ await session.send(await ctx.puppeteer.render(genImageHTML(hero, config.template_hero, "hero" /* Hero */)));
1232
1360
  } else
1233
1361
  throw 0;
1234
1362
  } catch (error) {
@@ -1355,7 +1483,7 @@ async function apply(ctx, config) {
1355
1483
  const commingMatches = scanningMatches.filter((item) => item.matchId == match.id);
1356
1484
  const realCommingMatches = commingMatches.filter((commingMatch, index, self) => index === self.findIndex((t) => t.guildId === commingMatch.guildId && t.platform === commingMatch.platform));
1357
1485
  let broadMatchMessage = "";
1358
- const img = await ctx.puppeteer.render(newGenMatchImageHTML(match, config.template_match));
1486
+ const img = await ctx.puppeteer.render(genImageHTML(match, config.template_match, "match" /* Match */));
1359
1487
  for (let comming of realCommingMatches) {
1360
1488
  let commingSubscribedPlayers = subscribedPlayersInGuild.filter((item) => item.platform == comming.platform && item.guildId == comming.guildId);
1361
1489
  let idsToFind = commingSubscribedPlayers.map((item) => item.steamId);
@@ -1394,20 +1522,18 @@ KDA:${((player.kills + player.assists) / (player.deaths || 1)).toFixed(2)} [${
1394
1522
  });
1395
1523
  }
1396
1524
  __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,
1525
+ function genImageHTML(data, template, type) {
1526
+ const templatePath = import_path2.default.join(`./node_modules/@sjtdev/koishi-plugin-${name}/template/${type}`, template + ".ejs");
1527
+ const templateData = {
1528
+ data,
1401
1529
  utils: utils_exports,
1402
1530
  ImageType,
1403
1531
  d2a: dotaconstants_add_exports,
1404
1532
  dotaconstants: dotaconstants3,
1405
- moment: import_moment.default,
1406
- sec2time,
1407
- formatNumber
1533
+ moment: import_moment.default
1408
1534
  };
1409
1535
  let result = "";
1410
- ejs.renderFile(templatePath, data, (err, html) => {
1536
+ ejs.renderFile(templatePath, templateData, (err, html) => {
1411
1537
  if (err)
1412
1538
  throw err;
1413
1539
  else
@@ -1417,380 +1543,7 @@ function newGenMatchImageHTML(match, template = "match_1") {
1417
1543
  import_fs2.default.writeFileSync("./node_modules/@sjtdev/koishi-plugin-dota2tracker/temp.html", result);
1418
1544
  return result;
1419
1545
  }
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");
1546
+ __name(genImageHTML, "genImageHTML");
1794
1547
  // Annotate the CommonJS export names for ESM import in node:
1795
1548
  0 && (module.exports = {
1796
1549
  Config,