@sjtdev/koishi-plugin-dota2tracker 1.2.16 → 1.2.17

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
@@ -73,9 +73,10 @@ __export(queries_exports, {
73
73
  MATCHES_FOR_DAILY: () => MATCHES_FOR_DAILY,
74
74
  MATCH_INFO: () => MATCH_INFO,
75
75
  PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD: () => PLAYERS_INFO_WITH_10_MATCHES_FOR_GUILD,
76
+ PLAYERS_LASTMATCH_RANKINFO: () => PLAYERS_LASTMATCH_RANKINFO,
76
77
  PLAYER_EXTRA_INFO: () => PLAYER_EXTRA_INFO,
77
78
  PLAYER_INFO_WITH_25_MATCHES: () => PLAYER_INFO_WITH_25_MATCHES,
78
- PLAYER_LASTMATCH: () => PLAYER_LASTMATCH,
79
+ REQUEST_MATCH_DATA_ANALYSIS: () => REQUEST_MATCH_DATA_ANALYSIS,
79
80
  VERIFYING_PLAYER: () => VERIFYING_PLAYER
80
81
  });
81
82
  var dotaconstants = __toESM(require("dotaconstants"));
@@ -257,29 +258,33 @@ function VERIFYING_PLAYER(steamAccountId) {
257
258
  `;
258
259
  }
259
260
  __name(VERIFYING_PLAYER, "VERIFYING_PLAYER");
260
- function PLAYER_LASTMATCH(steamAccountId) {
261
+ function PLAYERS_LASTMATCH_RANKINFO(steamAccountIds) {
261
262
  return `
262
- {
263
- player(steamAccountId: ${steamAccountId}) {
264
- steamAccount {
265
- id
266
- }
267
- matches(request: {take: 1}) {
268
- id
269
- parsedDateTime
270
- startDateTime
271
- players {
272
- steamAccount {
263
+ {
264
+ players(steamAccountIds:${JSON.stringify(steamAccountIds)}) {
265
+ steamAccount{
266
+ id
267
+ name
268
+ avatar
269
+ seasonRank
270
+ seasonLeaderboardRank
271
+ }
272
+ matches(request:{take:1}){
273
273
  id
274
+ parsedDateTime
275
+ startDateTime
276
+ players{
277
+ steamAccount{
278
+ id
279
+ }
280
+ }
274
281
  }
275
282
  }
276
283
  }
277
- }
278
- }
279
-
280
- `;
284
+
285
+ `;
281
286
  }
282
- __name(PLAYER_LASTMATCH, "PLAYER_LASTMATCH");
287
+ __name(PLAYERS_LASTMATCH_RANKINFO, "PLAYERS_LASTMATCH_RANKINFO");
283
288
  function PLAYER_INFO_WITH_25_MATCHES(steamAccountId, heroId) {
284
289
  return `
285
290
  {
@@ -517,6 +522,10 @@ function HERO_MATCHUP_WINRATE(heroId) {
517
522
  `;
518
523
  }
519
524
  __name(HERO_MATCHUP_WINRATE, "HERO_MATCHUP_WINRATE");
525
+ function REQUEST_MATCH_DATA_ANALYSIS(matchId) {
526
+ return `stratz{matchRetry(id:${matchId})}`;
527
+ }
528
+ __name(REQUEST_MATCH_DATA_ANALYSIS, "REQUEST_MATCH_DATA_ANALYSIS");
520
529
 
521
530
  // src/utils.ts
522
531
  var CONFIGS = { STRATZ_API: { URL: "https://api.stratz.com/graphql", TOKEN: "" } };
@@ -566,7 +575,7 @@ function getImageUrl(image, type = "local" /* Local */, format = "png" /* png */
566
575
  if (type === "local" /* Local */) {
567
576
  try {
568
577
  if (format === "svg" /* svg */) return import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.svg`);
569
- const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.png`);
578
+ const imageData = import_fs.default.readFileSync(`./node_modules/@sjtdev/koishi-plugin-dota2tracker/template/images/${image}.${format}`);
570
579
  const base64Data = imageData.toString("base64");
571
580
  return `data:image/png;base64,${base64Data}`;
572
581
  } catch (error) {
@@ -1235,6 +1244,20 @@ var Config = import_koishi.Schema.intersect([
1235
1244
  ])
1236
1245
  ).role("checkbox").description("在消息中附带链接,<br/>请选择消息类型:")
1237
1246
  }).description("基础设置"),
1247
+ import_koishi.Schema.intersect([
1248
+ import_koishi.Schema.object({
1249
+ rankBroadSwitch: import_koishi.Schema.boolean().default(false).description("段位变动播报")
1250
+ }),
1251
+ import_koishi.Schema.union([
1252
+ import_koishi.Schema.object({
1253
+ rankBroadSwitch: import_koishi.Schema.const(true).required(),
1254
+ rankBroadStar: import_koishi.Schema.boolean().default(true).description("星级变动播报"),
1255
+ rankBroadLeader: import_koishi.Schema.boolean().default(true).description("名词变动播报"),
1256
+ rankBroadFun: import_koishi.Schema.boolean().default(false).description("整活播报模板")
1257
+ }),
1258
+ import_koishi.Schema.object({})
1259
+ ])
1260
+ ]),
1238
1261
  import_koishi.Schema.intersect([
1239
1262
  import_koishi.Schema.object({
1240
1263
  dailyReportSwitch: import_koishi.Schema.boolean().default(false).description("日报功能")
@@ -1444,7 +1467,7 @@ async function apply(ctx, config) {
1444
1467
  let lastMatchId = 0;
1445
1468
  try {
1446
1469
  session.send("正在搜索对局详情,请稍后...");
1447
- lastMatchId = (await query(PLAYER_LASTMATCH(parseInt(flagBindedPlayer?.steamId ?? input_data)))).data.player.matches[0].id;
1470
+ lastMatchId = (await query(PLAYERS_LASTMATCH_RANKINFO(parseInt(flagBindedPlayer?.steamId ?? input_data)))).data.player.matches[0].id;
1448
1471
  } catch {
1449
1472
  session.send("获取玩家最近比赛失败。");
1450
1473
  return;
@@ -1669,19 +1692,10 @@ async function apply(ctx, config) {
1669
1692
  }
1670
1693
  __name(findingHero, "findingHero");
1671
1694
  ctx.on("ready", async () => {
1672
- const tables = await ctx.database.tables;
1673
- if (!("dt_subscribed_guilds" in tables)) {
1674
- ctx.model.extend("dt_subscribed_guilds", { id: "unsigned", guildId: "string", platform: "string" }, { autoInc: true });
1675
- }
1676
- if (!("dt_subscribed_players" in tables)) {
1677
- ctx.model.extend("dt_subscribed_players", { id: "unsigned", userId: "string", guildId: "string", platform: "string", steamId: "integer", nickName: "string" }, { autoInc: true });
1678
- }
1679
- if (!("dt_sended_match_id" in tables)) {
1680
- ctx.model.extend("dt_sended_match_id", { matchId: "unsigned", sendTime: "timestamp" }, { primary: "matchId" });
1681
- }
1682
- if (!("dt_previous_query_results" in tables)) {
1683
- ctx.model.extend("dt_previous_query_results", { matchId: "unsigned", data: "json", queryTime: "timestamp" }, { primary: "matchId" });
1684
- }
1695
+ ctx.model.extend("dt_subscribed_guilds", { id: "unsigned", guildId: "string", platform: "string" }, { autoInc: true });
1696
+ ctx.model.extend("dt_subscribed_players", { id: "unsigned", userId: "string", guildId: "string", platform: "string", steamId: "integer", nickName: "string", rank: "json" }, { autoInc: true });
1697
+ ctx.model.extend("dt_sended_match_id", { matchId: "unsigned", sendTime: "timestamp" }, { primary: "matchId" });
1698
+ ctx.model.extend("dt_previous_query_results", { matchId: "unsigned", data: "json", queryTime: "timestamp" }, { primary: "matchId" });
1685
1699
  ctx.cron("0 */6 * * *", () => {
1686
1700
  const oneMonthAgo = (0, import_moment.default)().subtract(1, "months").toDate();
1687
1701
  ctx.database.remove("dt_sended_match_id", { sendTime: { $lt: oneMonthAgo } });
@@ -1706,10 +1720,7 @@ async function apply(ctx, config) {
1706
1720
  const subscribedPlayersSteamIds = subscribedPlayersInGuild.map((player) => player.steamId).filter(function(value, index, self) {
1707
1721
  return self.indexOf(value) === index;
1708
1722
  });
1709
- const players = [];
1710
- for (let id of subscribedPlayersSteamIds) {
1711
- players.push((await query(PLAYER_LASTMATCH(id))).data.player);
1712
- }
1723
+ const players = (await query(PLAYERS_LASTMATCH_RANKINFO(subscribedPlayersSteamIds))).data.players;
1713
1724
  const lastMatches = players.map((player) => player.matches[0]).filter((item, index, self) => index === self.findIndex((t) => t.id === item.id)).filter((match) => import_moment.default.unix(match.startDateTime).isAfter((0, import_moment.default)().subtract(1, "days"))).filter((match) => !pendingMatches.some((pendingMatch) => pendingMatch.matchId == match.id));
1714
1725
  const sendedMatchesIds = (await ctx.database.get("dt_sended_match_id", { matchId: lastMatches.map((match) => match.id) }, ["matchId"])).map((match) => match.matchId);
1715
1726
  lastMatches.filter((match) => !sendedMatchesIds.includes(match.id)).forEach((match) => {
@@ -1724,10 +1735,61 @@ async function apply(ctx, config) {
1724
1735
  });
1725
1736
  });
1726
1737
  pendingMatches.push({ matchId: match.id, guilds: tempGuilds });
1738
+ query(REQUEST_MATCH_DATA_ANALYSIS(match.id));
1727
1739
  ctx.logger.info(
1728
1740
  tempGuilds.map((guild) => `追踪到来自群组${guild.platform}:${guild.guildId}的用户${guild.players.map((player) => `[${player.nickName ?? ""}(${player.steamId})]`).join("、")}的尚未播报过的最新比赛 ${match.id}。`).join("")
1729
1741
  );
1730
1742
  });
1743
+ const rankMap = players.reduce((map, player) => {
1744
+ map[player.steamAccount.id] = { rank: player.steamAccount.seasonRank, leader: player.steamAccount.seasonLeaderboardRank };
1745
+ return map;
1746
+ }, {});
1747
+ for (let subPlayer of subscribedPlayersInGuild) {
1748
+ if (subPlayer.rank.rank !== rankMap[subPlayer.steamId].rank || subPlayer.rank.leader !== rankMap[subPlayer.steamId].board) {
1749
+ if (Object.keys(subPlayer.rank).length != 0) {
1750
+ if (config.rankBroadSwitch) {
1751
+ const ranks = ["prevRank", "currRank"].reduce((acc, key) => {
1752
+ const source = key === "prevRank" ? subPlayer.rank : rankMap[subPlayer.steamId];
1753
+ acc[key] = {
1754
+ medal: parseInt(source.rank?.toString().split("")[0] ?? "0"),
1755
+ star: parseInt(source.rank?.toString().split("")[1] ?? "0"),
1756
+ leader: source.leader,
1757
+ inTop100: source.leader ? source.leader <= 10 ? "8c" : source.leader <= 100 ? "8b" : void 0 : void 0
1758
+ };
1759
+ return acc;
1760
+ }, {});
1761
+ const prevRank = ranks["prevRank"];
1762
+ const currRank = ranks["currRank"];
1763
+ if (prevRank.medal !== currRank.medal || prevRank.star !== currRank.star && config.rankBroadStar || prevRank.leader !== currRank.leader && config.rankBroadLeader) {
1764
+ const guildMember = await ctx.bots.find((bot) => bot.platform == subPlayer.platform)?.getGuildMember?.(subPlayer.guildId, subPlayer.userId);
1765
+ const name2 = subPlayer.nickName ?? guildMember?.nick ?? players.find((player) => player.steamAccount.id == subPlayer.steamId)?.steamAccount.name ?? subPlayer.steamId;
1766
+ const message = `群友 ${name2} 段位变动:${rank[prevRank.medal]}${prevRank.star} → ${rank[currRank.medal]}${currRank.star} `;
1767
+ if (config.rankBroadFun === true) {
1768
+ const img = await ctx.puppeteer.render(
1769
+ genImageHTML(
1770
+ {
1771
+ name: name2,
1772
+ avatar: guildMember?.avatar ?? players.find((player) => subPlayer.steamId == player.steamAccount.id).steamAccount.avatar,
1773
+ isRising: rankMap[subPlayer.steamId].rank > subPlayer.rank.rank || rankMap[subPlayer.steamId].rank == subPlayer.rank.rank && rankMap[subPlayer.steamId].leader < subPlayer.rank.leader || rankMap[subPlayer.steamId].leader > 0 && subPlayer.rank.leader == null,
1774
+ prevRank,
1775
+ currRank
1776
+ },
1777
+ "rank" + (config.rankBroadFun ? "_fun" : ""),
1778
+ "rank" /* Rank */
1779
+ )
1780
+ );
1781
+ await ctx.broadcast([`${subPlayer.platform}:${subPlayer.guildId}`], img);
1782
+ } else {
1783
+ const img = await ctx.puppeteer.render(genImageHTML(currRank, "rank" + (config.rankBroadFun ? "2" : ""), "rank" /* Rank */));
1784
+ await ctx.broadcast([`${subPlayer.platform}:${subPlayer.guildId}`], message + img);
1785
+ }
1786
+ ctx.logger.info(`向${subPlayer.platform}:${subPlayer.guildId}发布段位变动播报信息。`);
1787
+ }
1788
+ }
1789
+ }
1790
+ ctx.database.set("dt_subscribed_players", subPlayer.id, { rank: rankMap[subPlayer.steamId] });
1791
+ }
1792
+ }
1731
1793
  }
1732
1794
  if (pendingMatches.length > 0) {
1733
1795
  const now = (0, import_moment.default)();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sjtdev/koishi-plugin-dota2tracker",
3
3
  "description": "koishi插件-追踪群友的DOTA2对局",
4
- "version": "1.2.16",
4
+ "version": "1.2.17",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
Binary file
Binary file
@@ -0,0 +1,35 @@
1
+ <% const rank = data; %>
2
+ <head>
3
+ <style>
4
+ html,
5
+ body {
6
+ width: 128px;
7
+ height: 128px;
8
+ margin: 0;
9
+ padding: 0;
10
+ background-color: #0000;
11
+ }
12
+ div {
13
+ width: 128px;
14
+ height: 128px;
15
+ position: relative;
16
+ }
17
+ div > * {
18
+ position: absolute;
19
+ width: 100%;
20
+ }
21
+ p {
22
+ margin: 0;
23
+ text-align: center;
24
+ color: #fff;
25
+ bottom: 8px;
26
+ font-size: 20px;
27
+ text-shadow: -2px -2px 0 rgba(0, 0, 0, 0.5), 2px -2px 0 rgba(0, 0, 0, 0.5), -2px 2px 0 rgba(0, 0, 0, 0.5), 2px 2px 0 rgba(0, 0, 0, 0.5); /* 描边效果 */
28
+ }
29
+ </style>
30
+ </head>
31
+ <div>
32
+ <img src="<%= utils.getImageUrl('medal_' + (rank.inTop100 ?? rank.medal)) %>" />
33
+ <img src="<%= utils.getImageUrl("star_" + rank.star) %>" />
34
+ <p><%= rank.leader %></p>
35
+ </div>
@@ -0,0 +1,109 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Document</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+ html {
13
+ width: 1024px;
14
+ height: 768px;
15
+ }
16
+ body.xi {
17
+ background: url(../images/xi.jpg) no-repeat center center / cover;
18
+ }
19
+ body.bei {
20
+ background: url(../images/bei.jpg) no-repeat center center / cover;
21
+ }
22
+ .wrapper {
23
+ padding: 80px;
24
+ padding-top: 180px;
25
+ }
26
+ .wrapper > p {
27
+ font-size: 32px;
28
+ line-height: 48px;
29
+ height: 48px;
30
+ text-align: center;
31
+ }
32
+ body.xi p.bei,
33
+ body.bei p.xi {
34
+ display: none;
35
+ }
36
+ .wrapper > p > span {
37
+ margin: 0 10px;
38
+ }
39
+ .wrapper > p > span.prev {
40
+ color: gray;
41
+ }
42
+ .wrapper > p > span.curr {
43
+ font-weight: bold;
44
+ color: red;
45
+ }
46
+
47
+ .wrapper > p > img {
48
+ width: 48px;
49
+ height: 48px;
50
+ vertical-align: middle;
51
+ line-height: 48px;
52
+ }
53
+
54
+ .ranks {
55
+ margin-top: 40px;
56
+ display: flex;
57
+ width: 100%;
58
+ height: 256px;
59
+ justify-content: space-evenly;
60
+ }
61
+
62
+ div.rank {
63
+ position: relative;
64
+ width: 256px;
65
+ height: 256px;
66
+ }
67
+
68
+ div.rank > img {
69
+ position: absolute;
70
+ }
71
+
72
+ div.rank.prev {
73
+ filter: grayscale(1);
74
+ }
75
+ div.rank.curr {
76
+ transform: scale(1.25);
77
+ }
78
+ div.rank p {
79
+ font-size: 36px;
80
+ bottom: 20px;
81
+ width: 100%;
82
+ text-align: center;
83
+ color: #fff;
84
+ position: absolute;
85
+ }
86
+ </style>
87
+ </head>
88
+ <body class="bei">
89
+ <div class="wrapper">
90
+ <p class="xi">热烈祝贺群友 <img src="" alt="" />12414124141 在天梯中再获进步,</p>
91
+ <p class="xi">由<span class="rank prev">先锋2</span>升为<span class="rank curr">先锋2</span>,再接再厉,再创辉煌!</p>
92
+ <p class="bei"><img src="" alt="" /></p>
93
+ <p class="bei">寄</p>
94
+ <div class="ranks">
95
+ <div class="rank prev">
96
+ <img src="../images/medal_8.png" alt="" />
97
+ <img src="../images/star_2.png" alt="" />
98
+ <p>1111</p>
99
+ </div>
100
+ <div class="rank curr">
101
+ <img src="../images/medal_8.png" alt="" />
102
+ <img src="../images/star_1.png" alt="" />
103
+ <p>1111</p>
104
+ </div>
105
+ </div>
106
+ <p style="text-align: right; margin-top: 40px;">—— 2024/11/11 00点00分</p>
107
+ </div>
108
+ </body>
109
+ </html>
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Document</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ }
12
+ html {
13
+ width: 1024px;
14
+ height: 768px;
15
+ }
16
+ <%= ["xi","bei"].map(kind=>`body.${kind} {background: url(${utils.getImageUrl(kind, undefined, "jpg")}) no-repeat center center / cover;}`).join("\n") %>
17
+ .wrapper {
18
+ padding: 80px;
19
+ padding-top: 180px;
20
+ }
21
+ .wrapper > p {
22
+ font-size: 32px;
23
+ line-height: 48px;
24
+ height: 48px;
25
+ text-align: center;
26
+ }
27
+ body.xi p.bei,
28
+ body.bei p.xi {
29
+ display: none;
30
+ }
31
+ .wrapper > p > span {
32
+ margin: 0 10px;
33
+ }
34
+ .wrapper > p > span.prev {
35
+ color: gray;
36
+ }
37
+ .wrapper > p > span.curr {
38
+ font-weight: bold;
39
+ color: red;
40
+ }
41
+
42
+ .wrapper > p > img {
43
+ width: 48px;
44
+ height: 48px;
45
+ vertical-align: middle;
46
+ line-height: 48px;
47
+ }
48
+
49
+ .ranks {
50
+ margin-top: 40px;
51
+ display: flex;
52
+ width: 100%;
53
+ height: 256px;
54
+ justify-content: space-evenly;
55
+ }
56
+
57
+ div.rank {
58
+ position: relative;
59
+ width: 256px;
60
+ height: 256px;
61
+ }
62
+
63
+ div.rank > img {
64
+ position: absolute;
65
+ }
66
+
67
+ div.rank.prev {
68
+ filter: grayscale(1);
69
+ }
70
+ div.rank.curr {
71
+ transform: scale(1.25);
72
+ }
73
+ div.rank p {
74
+ font-size: 36px;
75
+ bottom: 20px;
76
+ width: 100%;
77
+ text-align: center;
78
+ color: #fff;
79
+ position: absolute;
80
+ }
81
+ </style>
82
+ </head>
83
+ <% const {name, avatar, isRising, prevRank, currRank} = data; %>
84
+ <body class="<%= isRising ? "xi" : "bei" %>">
85
+ <div class="wrapper">
86
+ <p class="xi">热烈祝贺群友 <img src="<%= avatar %>" /><%= name %> 在天梯中再获进步,</p>
87
+ <p class="xi">由
88
+ <span class="rank prev"><%= d2a.rank[prevRank.medal] %><%= prevRank.leader ?? prevRank.star %></span>升为
89
+ <span class="rank curr"><%= d2a.rank[currRank.medal] %><%= currRank.leader ?? currRank.star %></span>,再接再厉,再创辉煌!
90
+ </p>
91
+ <p class="bei"><img src="<%= avatar %>" /></p>
92
+ <p class="bei">寄</p>
93
+ <div class="ranks">
94
+ <div class="rank prev">
95
+ <img src="<%= utils.getImageUrl('medal_' +(prevRank.inTop100 ?? prevRank.medal)) %>" alt="" />
96
+ <img src="<%= utils.getImageUrl('star_' + prevRank.star) %>" alt="" />
97
+ <p><%= prevRank.leader ?? "" %></p>
98
+ </div>
99
+ <div class="rank curr">
100
+ <img src="<%= utils.getImageUrl('medal_' +(currRank.inTop100 ?? currRank.medal)) %>" alt="" />
101
+ <img src="<%= utils.getImageUrl('star_' + currRank.star) %>" alt="" />
102
+ <p><%= currRank.leader ?? "" %></p>
103
+ </div>
104
+ </div>
105
+ <p style="text-align: right; margin-top: 40px;">—— <%= moment().format('YYYY/MM/DD HH点mm分') %></p>
106
+ </div>
107
+ </body>
108
+ </html>