Skip to content

Commit f1dba97

Browse files
authored
feat: steam plugin (#621)
1 parent bc3c430 commit f1dba97

File tree

6 files changed

+428
-2
lines changed

6 files changed

+428
-2
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ print("run[CQ:image,file="+j["img"]+"]")
559559

560560
- [x] b站推送列表
561561

562-
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 10s"触发的指令)
562+
- [x] 拉取b站推送 (使用job执行定时任务------记录在"@every 5m"触发的指令)
563563

564564
</details>
565565
<details>
@@ -1283,6 +1283,22 @@ print("run[CQ:image,file="+j["img"]+"]")
12831283

12841284
- [x] 黄油角色[@xxx]
12851285

1286+
</details>
1287+
<details>
1288+
<summary>steam</summary>
1289+
1290+
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/steam"`
1291+
1292+
- [x] steam[添加|删除]订阅xxxxx
1293+
1294+
- [x] steam查看订阅
1295+
1296+
- [x] steam绑定 api key xxxxxxx
1297+
1298+
- [x] 查看apikey
1299+
1300+
- [x] 拉取steam订阅 (使用job执行定时任务------记录在"@every 1m"触发的指令)
1301+
12861302
</details>
12871303
<details>
12881304
<summary>抽塔罗牌</summary>

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ import (
131131
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime" // 来份涩图
132132
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shadiao" // 沙雕app
133133
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shindan" // 测定
134+
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/steam" // steam相关
134135
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tarot" // 抽塔罗牌
135136
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
136137
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番

plugin/bilibili/bilibili.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func init() {
5656
"- 查成分 [xxx]\n" +
5757
"- 查弹幕 [xxx]\n" +
5858
"- 设置b站cookie b_ut=7;buvid3=0;i-wanna-go-back=-1;innersign=0;\n" +
59-
"- 更新vup" +
59+
"- 更新vup\n" +
6060
"Tips: (412就是拦截的意思,建议私聊把cookie设全)\n",
6161
PublicDataFolder: "Bilibili",
6262
})

plugin/steam/listenter.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package steam
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"strings"
7+
"time"
8+
9+
"github.com/FloatTech/floatbox/binary"
10+
"github.com/FloatTech/floatbox/web"
11+
ctrl "github.com/FloatTech/zbpctrl"
12+
"github.com/tidwall/gjson"
13+
zero "github.com/wdvxdr1123/ZeroBot"
14+
"github.com/wdvxdr1123/ZeroBot/message"
15+
)
16+
17+
// ----------------------- 远程调用 ----------------------
18+
const (
19+
URL = "https://api.steampowered.com/" // steam API 调用地址
20+
StatusURL = "ISteamUser/GetPlayerSummaries/v2/?key=%+v&steamids=%+v" // 根据用户steamID获取用户状态
21+
steamapikeygid = 3
22+
)
23+
24+
var apiKey string
25+
26+
func init() {
27+
engine.OnRegex(`^steam绑定\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
28+
apiKey = ctx.State["regex_matched"].([]string)[1]
29+
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
30+
_ = m.Manager.Response(steamapikeygid)
31+
err := m.Manager.SetExtra(steamapikeygid, apiKey)
32+
if err != nil {
33+
ctx.SendChain(message.Text("[steam] ERROR: 保存apikey失败!"))
34+
return
35+
}
36+
ctx.SendChain(message.Text("保存apikey成功!"))
37+
})
38+
engine.OnFullMatch("查看apikey", zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
39+
ctx.SendChain(message.Text("apikey为: ", apiKey))
40+
})
41+
engine.OnFullMatch("拉取steam订阅", getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
42+
su := zero.BotConfig.SuperUsers[0]
43+
// 获取所有处于监听状态的用户信息
44+
infos, err := database.findAll()
45+
if err != nil {
46+
// 挂了就给管理员发消息
47+
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
48+
return
49+
}
50+
if len(infos) == 0 {
51+
return
52+
}
53+
// 收集这波用户的streamId,然后查当前的状态,并建立信息映射表
54+
streamIds := make([]string, len(infos))
55+
localPlayerMap := make(map[int64]*player)
56+
for i, info := range infos {
57+
streamIds[i] = strconv.FormatInt(info.SteamID, 10)
58+
localPlayerMap[info.SteamID] = info
59+
}
60+
// 将所有用户状态查一遍
61+
playerStatus, err := getPlayerStatus(streamIds...)
62+
if err != nil {
63+
// 出错就发消息
64+
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err))
65+
return
66+
}
67+
// 遍历返回的信息做对比,假如信息有变化则发消息
68+
now := time.Now()
69+
msg := make(message.Message, 0, len(playerStatus))
70+
for _, playerInfo := range playerStatus {
71+
msg = msg[:0]
72+
localInfo := localPlayerMap[playerInfo.SteamID]
73+
// 排除不需要处理的情况
74+
if localInfo.GameID == 0 && playerInfo.GameID == 0 {
75+
continue
76+
}
77+
// 打开游戏
78+
if localInfo.GameID == 0 && playerInfo.GameID != 0 {
79+
msg = append(msg, message.Text(playerInfo.PersonaName, "正在玩", playerInfo.GameExtraInfo))
80+
localInfo.LastUpdate = now.Unix()
81+
}
82+
// 更换游戏
83+
if localInfo.GameID != 0 && playerInfo.GameID != localInfo.GameID && playerInfo.GameID != 0 {
84+
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 丢下了", localInfo.GameExtraInfo, ", 转头去玩", playerInfo.GameExtraInfo))
85+
localInfo.LastUpdate = now.Unix()
86+
}
87+
// 关闭游戏
88+
if playerInfo.GameID != localInfo.GameID && playerInfo.GameID == 0 {
89+
msg = append(msg, message.Text(playerInfo.PersonaName, "玩了", (now.Unix()-localInfo.LastUpdate)/60, "分钟后, 关掉了", localInfo.GameExtraInfo))
90+
localInfo.LastUpdate = 0
91+
}
92+
if len(msg) != 0 {
93+
groups := strings.Split(localInfo.Target, ",")
94+
for _, groupString := range groups {
95+
group, err := strconv.ParseInt(groupString, 10, 64)
96+
if err != nil {
97+
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nOTHER: SteamID ", localInfo.SteamID))
98+
continue
99+
}
100+
ctx.SendGroupMessage(group, msg)
101+
}
102+
}
103+
// 更新数据
104+
localInfo.GameID = playerInfo.GameID
105+
localInfo.GameExtraInfo = playerInfo.GameExtraInfo
106+
if err = database.update(localInfo); err != nil {
107+
ctx.SendPrivateMessage(su, message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据失败\nOTHER: SteamID ", localInfo.SteamID))
108+
}
109+
}
110+
})
111+
}
112+
113+
// getPlayerStatus 获取用户状态
114+
func getPlayerStatus(streamIds ...string) ([]*player, error) {
115+
players := make([]*player, 0)
116+
// 拼接请求地址
117+
url := fmt.Sprintf(URL+StatusURL, apiKey, strings.Join(streamIds, ","))
118+
// 拉取并解析数据
119+
data, err := web.GetData(url)
120+
if err != nil {
121+
return players, err
122+
}
123+
dataStr := binary.BytesToString(data)
124+
index := gjson.Get(dataStr, "response.players.#").Uint()
125+
for i := uint64(0); i < index; i++ {
126+
players = append(players, &player{
127+
SteamID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.steamid", i)).Int(),
128+
PersonaName: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.personaname", i)).String(),
129+
GameID: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameid", i)).Int(),
130+
GameExtraInfo: gjson.Get(dataStr, fmt.Sprintf("response.players.%d.gameextrainfo", i)).String(),
131+
})
132+
}
133+
return players, nil
134+
}

plugin/steam/steam.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// Package steam 获取steam用户状态
2+
package steam
3+
4+
import (
5+
"strconv"
6+
"strings"
7+
"time"
8+
9+
"github.com/FloatTech/floatbox/binary"
10+
"github.com/FloatTech/floatbox/math"
11+
ctrl "github.com/FloatTech/zbpctrl"
12+
"github.com/FloatTech/zbputils/control"
13+
"github.com/FloatTech/zbputils/ctxext"
14+
"github.com/FloatTech/zbputils/img/text"
15+
zero "github.com/wdvxdr1123/ZeroBot"
16+
"github.com/wdvxdr1123/ZeroBot/message"
17+
)
18+
19+
var (
20+
engine = control.Register("steam", &ctrl.Options[*zero.Ctx]{
21+
DisableOnDefault: false,
22+
Brief: "steam相关插件",
23+
Help: "- steam添加订阅 xxxxxxx (可输入需要绑定的 steamid)\n" +
24+
"- steam删除订阅 xxxxxxx (删除你创建的对于 steamid 的绑定)\n" +
25+
"- steam查询订阅 (查询本群内所有的绑定对象)\n" +
26+
"-----------------------\n" +
27+
"- steam绑定 api key xxxxxxx (密钥在steam网站申请, 申请地址: https://steamcommunity.com/dev/registerkey)\n" +
28+
"- 查看apikey (查询已经绑定的密钥)\n" +
29+
"- 拉取steam订阅 (使用插件定时任务开始)\n" +
30+
"-----------------------\n" +
31+
"Tips: steamID在用户资料页的链接上面, 形如7656119820673xxxx\n" +
32+
"需要先私聊绑定apikey, 订阅用户之后使用job插件设置定时, 例: \n" +
33+
"记录在\"@every 1m\"触发的指令\n" +
34+
"拉取steam订阅",
35+
PrivateDataFolder: "steam",
36+
}).ApplySingle(ctxext.DefaultSingle)
37+
)
38+
39+
func init() {
40+
// 创建绑定流程
41+
engine.OnRegex(`^steam添加订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
42+
steamidstr := ctx.State["regex_matched"].([]string)[1]
43+
steamID := math.Str2Int64(steamidstr)
44+
// 获取用户状态
45+
playerStatus, err := getPlayerStatus(steamidstr)
46+
if err != nil {
47+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败, 获取用户信息错误"))
48+
return
49+
}
50+
if len(playerStatus) == 0 {
51+
ctx.SendChain(message.Text("[steam] ERROR: 需要添加的用户不存在, 请检查id或url"))
52+
return
53+
}
54+
playerData := playerStatus[0]
55+
// 判断用户是否已经初始化:若未初始化,通过用户的steamID获取当前状态并初始化;若已经初始化则更新用户信息
56+
info, err := database.find(steamID)
57+
if err != nil {
58+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 添加失败,数据库错误"))
59+
return
60+
}
61+
// 处理数据
62+
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
63+
if info.Target == "" {
64+
info = player{
65+
SteamID: steamID,
66+
PersonaName: playerData.PersonaName,
67+
Target: groupID,
68+
GameID: playerData.GameID,
69+
GameExtraInfo: playerData.GameExtraInfo,
70+
LastUpdate: time.Now().Unix(),
71+
}
72+
} else if !strings.Contains(info.Target, groupID) {
73+
info.Target = strings.Join([]string{info.Target, groupID}, ",")
74+
}
75+
// 更新数据库
76+
if err = database.update(&info); err != nil {
77+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 更新数据库失败"))
78+
return
79+
}
80+
ctx.SendChain(message.Text("添加成功"))
81+
})
82+
// 删除绑定流程
83+
engine.OnRegex(`^steam删除订阅\s*(\d+)$`, zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
84+
steamID := math.Str2Int64(ctx.State["regex_matched"].([]string)[1])
85+
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
86+
// 判断是否已经绑定该steamID,若已绑定就将群列表从推送群列表钟去除
87+
info, err := database.findWithGroupID(steamID, groupID)
88+
if err != nil {
89+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
90+
return
91+
}
92+
if info.SteamID == 0 {
93+
ctx.SendChain(message.Text("[steam] ERROR: 所需要删除的用户不存在。"))
94+
return
95+
}
96+
// 从绑定列表中剔除需要删除的对象
97+
targets := strings.Split(info.Target, ",")
98+
newTargets := make([]string, 0)
99+
for _, target := range targets {
100+
if target == groupID {
101+
continue
102+
}
103+
newTargets = append(newTargets, target)
104+
}
105+
if len(newTargets) == 0 {
106+
if err = database.del(steamID); err != nil {
107+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
108+
return
109+
}
110+
} else {
111+
info.Target = strings.Join(newTargets, ",")
112+
if err = database.update(&info); err != nil {
113+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 删除失败,数据库错误"))
114+
return
115+
}
116+
}
117+
ctx.SendChain(message.Text("删除成功"))
118+
})
119+
// 查询当前群绑定信息
120+
engine.OnFullMatch("steam查询订阅", zero.OnlyGroup, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
121+
// 获取群信息
122+
groupID := strconv.FormatInt(ctx.Event.GroupID, 10)
123+
// 获取所有绑定信息
124+
infos, err := database.findAll()
125+
if err != nil {
126+
ctx.SendChain(message.Text("[steam] ERROR: ", err, "\nEXP: 查询订阅失败, 数据库错误"))
127+
return
128+
}
129+
if len(infos) == 0 {
130+
ctx.SendChain(message.Text("[steam] ERROR: 还未订阅过用户关系!"))
131+
return
132+
}
133+
// 遍历所有信息,如果包含该群就收集对应的steamID
134+
var sb strings.Builder
135+
head := " 查询steam订阅成功, 该群订阅的用户有: \n"
136+
sb.WriteString(head)
137+
for _, info := range infos {
138+
if strings.Contains(info.Target, groupID) {
139+
sb.WriteString(" ")
140+
sb.WriteString(info.PersonaName)
141+
sb.WriteString(":")
142+
sb.WriteString(strconv.FormatInt(info.SteamID, 10))
143+
sb.WriteString("\n")
144+
}
145+
}
146+
if sb.String() == head {
147+
ctx.SendChain(message.Text("查询成功,该群暂时还没有被绑定的用户!"))
148+
return
149+
}
150+
// 组装并返回结果
151+
data, err := text.RenderToBase64(sb.String(), text.FontFile, 400, 18)
152+
if err != nil {
153+
ctx.SendChain(message.Text("[steam] ERROR: ", err))
154+
return
155+
}
156+
ctx.SendChain(message.Image("base64://" + binary.BytesToString(data)))
157+
})
158+
}

0 commit comments

Comments
 (0)