koishi-plugin-tmp-bot 1.16.0 → 1.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ const guildBind = require('../database/guildBind')
2
+ const truckersMpApi = require("../api/truckersMpApi");
3
+
4
+ /**
5
+ * 绑定 TMP ID
6
+ */
7
+ module.exports = async (ctx, cfg, session, tmpId) => {
8
+ if (!tmpId || isNaN(tmpId)) {
9
+ return `请输入正确的玩家编号`
10
+ }
11
+
12
+ // 查询玩家信息
13
+ let playerInfo = await truckersMpApi.player(ctx.http, tmpId)
14
+ if (playerInfo.error) {
15
+ return '绑定失败 (查询玩家信息失败)'
16
+ }
17
+
18
+ // 更新数据库
19
+ guildBind.saveOrUpdate(ctx.database, session.platform, session.userId, tmpId)
20
+
21
+ return `绑定成功 ( ${playerInfo.data.name} )`
22
+ }
@@ -0,0 +1,31 @@
1
+ const { segment } = require('koishi')
2
+ const { resolve } = require('path')
3
+ const common = require('../util/common')
4
+
5
+ module.exports = async (ctx, session) => {
6
+ if (!ctx.puppeteer) {
7
+ return '未启用 Puppeteer 功能'
8
+ }
9
+
10
+ let page
11
+ try {
12
+ page = await ctx.puppeteer.page()
13
+ await page.setViewport({ width: 1000, height: 1000 })
14
+ await page.goto(`file:///${resolve(__dirname, '../resource/dlc.html')}`)
15
+ await page.waitForNetworkIdle()
16
+ await common.sleep(500)
17
+ const element = await page.$("#dlc-info-container");
18
+ return (
19
+ segment.image(await element.screenshot({
20
+ encoding: "binary"
21
+ }), "image/jpg")
22
+ )
23
+ } catch (e) {
24
+ console.info(e)
25
+ return '渲染异常,请重试'
26
+ } finally {
27
+ if (page) {
28
+ await page.close()
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,107 @@
1
+ const { segment } = require('koishi')
2
+ const { resolve } = require('path')
3
+ const guildBind = require('../database/guildBind')
4
+ const truckyAppApi = require('../api/truckyAppApi')
5
+ const truckersMpApi = require('../api/truckersMpApi')
6
+ const evmOpenApi = require('../api/evmOpenApi')
7
+ const baiduTranslate = require('../util/baiduTranslate')
8
+ const common = require('../util/common')
9
+
10
+ /**
11
+ * 定位
12
+ */
13
+ module.exports = async (ctx, cfg, session, tmpId) => {
14
+ if (ctx.puppeteer) {
15
+ if (tmpId && isNaN(tmpId)) {
16
+ return `请输入正确的玩家编号`
17
+ }
18
+
19
+ // 如果没有传入tmpId,尝试从数据库查询绑定信息
20
+ if (!tmpId) {
21
+ let guildBindData = await guildBind.get(ctx.database, session.platform, session.userId)
22
+ if (!guildBindData) {
23
+ return `请输入正确的玩家编号`
24
+ }
25
+ tmpId = guildBindData.tmp_id
26
+ }
27
+
28
+ // 查询玩家信息
29
+ let playerInfo = await truckersMpApi.player(ctx.http, tmpId)
30
+ if (playerInfo.error) {
31
+ return '查询玩家信息失败,请重试'
32
+ }
33
+
34
+ // 查询线上信息
35
+ let playerMapInfo = await truckyAppApi.online(ctx.http, tmpId)
36
+ if (playerMapInfo.error) {
37
+ return '查询玩家信息失败,请重试'
38
+ }
39
+ if (!playerMapInfo.data.online) {
40
+ return '玩家离线'
41
+ }
42
+
43
+ // 查询周边玩家,并处理数据
44
+ let areaPlayersData = await evmOpenApi.mapPlayerList(ctx.http, playerMapInfo.data.server,
45
+ playerMapInfo.data.x - 4000,
46
+ playerMapInfo.data.y + 2500,
47
+ playerMapInfo.data.x + 4000,
48
+ playerMapInfo.data.y - 2500)
49
+ let areaPlayerList = []
50
+ if (!areaPlayersData.error) {
51
+ areaPlayerList = areaPlayersData.data
52
+ let index = areaPlayerList.findIndex((player) => {
53
+ return player.tmpId.toString() === tmpId.toString()
54
+ })
55
+ if (index !== -1) {
56
+ areaPlayerList.splice(index, 1)
57
+ }
58
+ }
59
+ areaPlayerList.push({
60
+ axisX: playerMapInfo.data.x,
61
+ axisY: playerMapInfo.data.y,
62
+ tmpId
63
+ })
64
+
65
+ // promods服ID集合
66
+ let promodsServerIdList = [50, 51]
67
+
68
+ // 构建地图数据
69
+ let data = {
70
+ mapType: promodsServerIdList.indexOf(playerMapInfo.data.server) !== -1 ? 'promods' : 'ets',
71
+ avatar: playerInfo.data.smallAvatar,
72
+ username: playerInfo.data.name,
73
+ serverName: playerMapInfo.data.serverDetails.name,
74
+ country: await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.country),
75
+ realName: await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.realName),
76
+ currentPlayerId: tmpId,
77
+ centerX: playerMapInfo.data.x,
78
+ centerY: playerMapInfo.data.y,
79
+ playerList: areaPlayerList
80
+ }
81
+
82
+ let page
83
+ try {
84
+ page = await ctx.puppeteer.page()
85
+ await page.setViewport({ width: 1000, height: 1000 })
86
+ await page.goto(`file:///${resolve(__dirname, '../resource/position.html')}`)
87
+ await page.evaluate(`setData(${JSON.stringify(data)})`)
88
+ await common.sleep(100)
89
+ await page.waitForNetworkIdle()
90
+ const element = await page.$("#container");
91
+ return (
92
+ segment.image(await element.screenshot({
93
+ encoding: "binary"
94
+ }), "image/jpg")
95
+ )
96
+ } catch (e) {
97
+ return '渲染异常,请重试'
98
+ } finally {
99
+ if (page) {
100
+ await page.close()
101
+ }
102
+ }
103
+
104
+ } else {
105
+ return '未启用 puppeteer 服务'
106
+ }
107
+ }
@@ -0,0 +1,13 @@
1
+ const tmpQueryText = require("./tmpQueryText");
2
+ const tmpQueryImg = require("./tmpQueryImg");
3
+
4
+ module.exports = async (ctx, cfg, session, tmpId) => {
5
+ switch (cfg.tmpQueryType) {
6
+ case 1:
7
+ return await tmpQueryText(ctx, cfg, session, tmpId)
8
+ case 2:
9
+ return await tmpQueryImg(ctx, cfg, session, tmpId)
10
+ default:
11
+ return '指令配置错误'
12
+ }
13
+ }
@@ -0,0 +1,108 @@
1
+ const dayjs = require('dayjs')
2
+ const guildBind = require('../../database/guildBind')
3
+ const truckyAppApi = require('../../api/truckyAppApi')
4
+ const evmOpenApi = require('../../api/evmOpenApi')
5
+ const baiduTranslate = require('../../util/baiduTranslate')
6
+ const {resolve} = require("path");
7
+ const common = require("../../util/common");
8
+ const {segment} = require("koishi");
9
+
10
+ /**
11
+ * 用户组
12
+ */
13
+ const userGroup = {
14
+ 'Player': '玩家',
15
+ 'Retired Legend': '退役',
16
+ 'Game Developer': '游戏开发者',
17
+ 'Retired Team Member': '退休团队成员',
18
+ 'Add-On Team': '附加组件团队',
19
+ 'Game Moderator': '游戏管理员'
20
+ }
21
+
22
+ /**
23
+ * 查询玩家信息
24
+ */
25
+ module.exports = async (ctx, cfg, session, tmpId) => {
26
+ if (!ctx.puppeteer) {
27
+ return '未启用 puppeteer 服务'
28
+ }
29
+
30
+ if (tmpId && isNaN(tmpId)) {
31
+ return `请输入正确的玩家编号`
32
+ }
33
+
34
+ // 如果没有传入tmpId,尝试从数据库查询绑定信息
35
+ if (!tmpId) {
36
+ let guildBindData = await guildBind.get(ctx.database, session.platform, session.userId)
37
+ if (!guildBindData) {
38
+ return `请输入正确的玩家编号`
39
+ }
40
+ tmpId = guildBindData.tmp_id
41
+ }
42
+
43
+ // 查询玩家信息
44
+ let playerInfo = await evmOpenApi.playerInfo(ctx.http, tmpId)
45
+ if (playerInfo.error) {
46
+ return '查询玩家信息失败,请重试'
47
+ }
48
+
49
+ // 查询线上信息
50
+ let playerMapInfo = await truckyAppApi.online(ctx.http, tmpId)
51
+
52
+ // 拼接数据
53
+ let data = {}
54
+ data.tmpId = playerInfo.data.tmpId
55
+ data.name = playerInfo.data.name
56
+ data.steamId = playerInfo.data.steamId
57
+ data.registerDate = dayjs(playerInfo.data.registerTime).format('YYYY年MM月DD日')
58
+ data.avatarUrl = playerInfo.data.avatarUrl
59
+ data.groupColor = playerInfo.data.groupColor
60
+ data.groupName = (userGroup[playerInfo.data.groupName] || playerInfo.data.groupName)
61
+ data.isJoinVtc = playerInfo.data.isJoinVtc
62
+ data.vtcName = playerInfo.data.vtcName
63
+ data.vtcRole = playerInfo.data.vtcRole
64
+ data.isSponsor = playerInfo.data.isSponsor
65
+ data.sponsorAmount = playerInfo.data.sponsorAmount
66
+ data.sponsorCumulativeAmount = playerInfo.data.sponsorCumulativeAmount
67
+ data.sponsorHide = playerInfo.data.sponsorHide
68
+ data.isOnline = false
69
+ if (playerMapInfo && !playerMapInfo.error) {
70
+ data.isOnline = playerMapInfo.data.online
71
+ if (data.isOnline) {
72
+ data.onlineServerName = playerMapInfo.data.serverDetails.name
73
+ data.onlineCountry = await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.country)
74
+ data.onlineCity = await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.realName)
75
+ data.onlineX = playerMapInfo.data.x
76
+ data.onlineY = playerMapInfo.data.y
77
+ data.onlineMapType = playerMapInfo.data.serverDetails.id === 50 ? 'promods' : 'ets'
78
+ }
79
+ }
80
+ data.isBan = playerInfo.data.isBan
81
+ data.banUntil = playerInfo.data.banUntil
82
+ data.banReason = playerInfo.data.banReason
83
+ data.banReasonZh = playerInfo.data.banReasonZh
84
+ data.banCount = playerInfo.data.banCount
85
+ data.banHide = playerInfo.data.banHide
86
+
87
+ let page
88
+ try {
89
+ page = await ctx.puppeteer.page()
90
+ await page.setViewport({ width: 1000, height: 1000 })
91
+ await page.goto(`file:///${resolve(__dirname, '../../resource/query.html')}`)
92
+ await page.evaluate(`init(${JSON.stringify(data)})`)
93
+ await common.sleep(100)
94
+ await page.waitForNetworkIdle()
95
+ const element = await page.$("#container");
96
+ return (
97
+ segment.image(await element.screenshot({
98
+ encoding: "binary"
99
+ }), "image/jpg")
100
+ )
101
+ } catch {
102
+ return '渲染异常,请重试'
103
+ } finally {
104
+ if (page) {
105
+ await page.close()
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,94 @@
1
+ const dayjs = require('dayjs')
2
+ const guildBind = require('../../database/guildBind')
3
+ const truckyAppApi = require('../../api/truckyAppApi')
4
+ const evmOpenApi = require('../../api/evmOpenApi')
5
+ const baiduTranslate = require('../../util/baiduTranslate')
6
+
7
+ /**
8
+ * 用户组
9
+ */
10
+ const userGroup = {
11
+ 'Player': '玩家',
12
+ 'Retired Legend': '退役',
13
+ 'Game Developer': '游戏开发者',
14
+ 'Retired Team Member': '退休团队成员',
15
+ 'Add-On Team': '附加组件团队',
16
+ 'Game Moderator': '游戏管理员'
17
+ }
18
+
19
+ /**
20
+ * 查询玩家信息
21
+ */
22
+ module.exports = async (ctx, cfg, session, tmpId) => {
23
+ if (tmpId && isNaN(tmpId)) {
24
+ return `请输入正确的玩家编号`
25
+ }
26
+
27
+ // 如果没有传入tmpId,尝试从数据库查询绑定信息
28
+ if (!tmpId) {
29
+ let guildBindData = await guildBind.get(ctx.database, session.platform, session.userId)
30
+ if (!guildBindData) {
31
+ return `请输入正确的玩家编号`
32
+ }
33
+ tmpId = guildBindData.tmp_id
34
+ }
35
+
36
+ // 查询玩家信息
37
+ let playerInfo = await evmOpenApi.playerInfo(ctx.http, tmpId)
38
+ if (playerInfo.error) {
39
+ return '查询玩家信息失败,请重试'
40
+ }
41
+
42
+ // 查询线上信息
43
+ let playerMapInfo = await truckyAppApi.online(ctx.http, tmpId)
44
+
45
+ // 拼接消息模板
46
+ let message = ''
47
+ if (cfg.queryShowAvatarEnable) {
48
+ message += `<img src="${playerInfo.data.avatarUrl}"/>\n`
49
+ }
50
+ message += '🆔TMP编号: ' + playerInfo.data.tmpId
51
+ message += '\n😀玩家名称: ' + playerInfo.data.name
52
+ message += '\n🎮SteamID: ' + playerInfo.data.steamId
53
+ let registerDate = dayjs(playerInfo.data.registerTime)
54
+ message += '\n📑注册日期: ' + registerDate.format('YYYY年MM月DD日') + ` (${dayjs().diff(registerDate, 'day')}天)`
55
+ message += '\n💼所属分组: ' + (userGroup[playerInfo.data.groupName] || playerInfo.data.groupName)
56
+ if (playerInfo.data.isJoinVtc) {
57
+ message += '\n🚚所属车队: ' + playerInfo.data.vtcName
58
+ message += '\n🚚车队角色: ' + playerInfo.data.vtcRole
59
+ }
60
+ message += '\n🚫是否封禁: ' + (playerInfo.data.isBan ? '是' : '否')
61
+ if (playerInfo.data.isBan) {
62
+ message += '\n🚫封禁截止: '
63
+ if (playerInfo.data.banHide) {
64
+ message += '隐藏'
65
+ } else {
66
+ if (!playerInfo.data.banUntil) {
67
+ message += '永久'
68
+ } else {
69
+ message += dayjs(playerInfo.data.banUntil).format('YYYY年MM月DD日 HH:mm')
70
+ }
71
+ message += "\n🚫封禁原因: " + (playerInfo.data.banReasonZh || playerInfo.data.banReason)
72
+ }
73
+ }
74
+ message += '\n🚫封禁次数: ' + playerInfo.data.banCount || 0
75
+ if (playerMapInfo && !playerMapInfo.error) {
76
+ message += '\n📶在线状态: ' + (playerMapInfo.data.online ? `在线🟢 (${playerMapInfo.data.serverDetails.name})` : '离线⚫')
77
+ if (playerMapInfo.data.online) {
78
+ message += '\n🌍线上位置: '
79
+ message += await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.country)
80
+ message += ' - '
81
+ message += await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.realName)
82
+ }
83
+ }
84
+ if (playerInfo.data.isSponsor) {
85
+ message += '\n🎁赞助用户'
86
+ if (!playerInfo.data.sponsorHide) {
87
+ message += `: \$${Math.floor(playerInfo.data.sponsorAmount / 100)}`
88
+ }
89
+ }
90
+ if (playerInfo.data.sponsorCumulativeAmount) {
91
+ message += '\n🎁累计赞助: $' + Math.floor(playerInfo.data.sponsorCumulativeAmount / 100)
92
+ }
93
+ return message
94
+ }
@@ -0,0 +1,37 @@
1
+ const truckersMpApi = require('../api/truckersMpApi')
2
+ const evmOpenApi = require('../api/evmOpenApi')
3
+
4
+ module.exports = async (ctx) => {
5
+ // 查询服务器信息
6
+ let serverData = await evmOpenApi.serverList(ctx.http)
7
+ if (serverData.error) {
8
+ return '查询服务器失败,请稍后重试'
9
+ }
10
+
11
+ // 构建消息
12
+ let message = ''
13
+ for (let server of serverData.data) {
14
+ // 如果前面有内容,换行
15
+ if (message) {
16
+ message += '\n\n'
17
+ }
18
+
19
+ message += '服务器: ' + ( server.isOnline === 1 ? '🟢' : '⚫' ) + server.serverName
20
+ message += `\n玩家人数: ${server.playerCount}/${server.maxPlayer}`
21
+ if (server.queue) {
22
+ message += ` (队列: ${server.queueCount})`
23
+ }
24
+ // 服务器特性
25
+ let characteristicList = []
26
+ if (!(server.afkEnable === 1)) {
27
+ characteristicList.push('⏱挂机')
28
+ }
29
+ if (server.collisionsEnable === 1) {
30
+ characteristicList.push('💥碰撞')
31
+ }
32
+ if (characteristicList && characteristicList.length > 0) {
33
+ message += '\n服务器特性: ' + characteristicList.join(' ')
34
+ }
35
+ }
36
+ return message
37
+ }
@@ -0,0 +1,16 @@
1
+ const tmpTrafficMap = require("./tmpTrafficMap");
2
+ const tmpTrafficText = require("./tmpTrafficText");
3
+
4
+ /**
5
+ * 查询路况
6
+ */
7
+ module.exports = async (ctx, cfg, serverName) => {
8
+ switch (cfg.tmpTrafficType) {
9
+ case 1:
10
+ return await tmpTrafficText(ctx, cfg, serverName)
11
+ case 2:
12
+ return await tmpTrafficMap(ctx, cfg, serverName)
13
+ default:
14
+ return '指令配置错误'
15
+ }
16
+ }
@@ -0,0 +1,128 @@
1
+ const truckyAppApi = require('../../api/truckyAppApi')
2
+ const evmOpenApi = require('../../api/evmOpenApi')
3
+ const baiduTranslate = require('../../util/baiduTranslate')
4
+ const {resolve} = require("path");
5
+ const common = require("../../util/common");
6
+ const {segment} = require("koishi");
7
+
8
+ /**
9
+ * 服务器别名
10
+ */
11
+ const serverAlias = {
12
+ 's1': {
13
+ name: 'sim1',
14
+ mapType: 'ets',
15
+ serverId: 2,
16
+ bounds: [[-94189, 93775], [79264, -78999]]
17
+ },
18
+ 's2': {
19
+ name: 'sim2',
20
+ mapType: 'ets',
21
+ serverId: 41,
22
+ bounds: [[-94189, 93775], [79264, -78999]]
23
+ },
24
+ 'p': {
25
+ name: 'eupromods1',
26
+ mapType: 'promods',
27
+ serverId: 50,
28
+ bounds: [[-96355, 16381], [205581, -70750]]
29
+ },
30
+ 'a': {
31
+ name: 'arc1',
32
+ mapType: 'ets',
33
+ serverId: 7,
34
+ bounds: [[-94189, 93775], [79264, -78999]]
35
+ }
36
+ }
37
+
38
+ /**
39
+ * 路况程度转中文
40
+ */
41
+ const severityToZh = {
42
+ 'Fluid': {
43
+ text: '畅通',
44
+ color: '#00d26a'
45
+ },
46
+ 'Moderate': {
47
+ text: '正常',
48
+ color: '#ff6723'
49
+ },
50
+ 'Congested': {
51
+ text: '缓慢',
52
+ color: '#f8312f'
53
+ },
54
+ 'Heavy': {
55
+ text: '拥堵',
56
+ color: '#8d67c5'
57
+ }
58
+ }
59
+
60
+ /**
61
+ * 位置类型转中文
62
+ */
63
+ const typeToZh = {
64
+ 'City': '城市',
65
+ 'Road': '公路',
66
+ 'Intersection': '十字路口'
67
+ }
68
+
69
+ /**
70
+ * 查询路况
71
+ */
72
+ module.exports = async (ctx, cfg, serverName) => {
73
+ if (!ctx.puppeteer) {
74
+ return '未启用 puppeteer 服务'
75
+ }
76
+
77
+ // 根据别名获取服务器信息
78
+ let serverInfo = serverAlias[serverName]
79
+ if (!serverInfo) {
80
+ return '请输入正确的服务器名称 (s1, s2, p, a)'
81
+ }
82
+
83
+ // 查询路况信息
84
+ let trafficData = await truckyAppApi.trafficTop(ctx.http, serverInfo.name)
85
+ if (trafficData.error) {
86
+ return '查询路况信息失败'
87
+ }
88
+
89
+ // 查询地图玩家数据
90
+ let mapData = await evmOpenApi.mapPlayerList(ctx.http, serverInfo.serverId, serverInfo.bounds[0][0], serverInfo.bounds[0][1], serverInfo.bounds[1][0], serverInfo.bounds[1][1])
91
+
92
+ // 构建路况数据
93
+ let data = {
94
+ mapType: serverInfo.mapType,
95
+ trafficList: [],
96
+ playerCoordinateList: mapData.error && mapData.data ? [] : mapData.data.map(item => [item.axisX, item.axisY])
97
+ }
98
+ for (const traffic of trafficData.data) {
99
+ data.trafficList.push({
100
+ country: await baiduTranslate(ctx, cfg, traffic.country),
101
+ province: await baiduTranslate(ctx, cfg, traffic.name.substring(0, traffic.name.lastIndexOf('(') - 1)),
102
+ playerCount: traffic.players,
103
+ severity: severityToZh[traffic.newSeverity] || { text: '未知', color: '#ffffff' }
104
+ })
105
+ }
106
+
107
+ let page
108
+ try {
109
+ page = await ctx.puppeteer.page()
110
+ await page.setViewport({ width: 1000, height: 1000 })
111
+ await page.goto(`file:///${resolve(__dirname, '../../resource/traffic.html')}`)
112
+ await page.evaluate(`setData(${JSON.stringify(data)})`)
113
+ await common.sleep(100)
114
+ await page.waitForNetworkIdle()
115
+ const element = await page.$("#container");
116
+ return (
117
+ segment.image(await element.screenshot({
118
+ encoding: "binary"
119
+ }), "image/jpg")
120
+ )
121
+ } catch {
122
+ return '渲染异常,请重试'
123
+ } finally {
124
+ if (page) {
125
+ await page.close()
126
+ }
127
+ }
128
+ }
@@ -0,0 +1,66 @@
1
+ const truckyAppApi = require('../../api/truckyAppApi')
2
+ const baiduTranslate = require('../../util/baiduTranslate')
3
+
4
+ /**
5
+ * 服务器别名
6
+ */
7
+ const serverNameAlias = {
8
+ 's1': 'sim1',
9
+ 's2': 'sim2',
10
+ 'p': 'eupromods1',
11
+ 'a': 'arc1'
12
+ }
13
+
14
+ /**
15
+ * 路况程度转中文
16
+ */
17
+ const severityToZh = {
18
+ 'Fluid': '🟢畅通',
19
+ 'Moderate': '🟠正常',
20
+ 'Congested': '🔴缓慢',
21
+ 'Heavy': '🟣拥堵'
22
+ }
23
+
24
+ /**
25
+ * 位置类型转中文
26
+ */
27
+ const typeToZh = {
28
+ 'City': '城市',
29
+ 'Road': '公路',
30
+ 'Intersection': '十字路口'
31
+ }
32
+
33
+ /**
34
+ * 查询路况
35
+ */
36
+ module.exports = async (ctx, cfg, serverName) => {
37
+ // 转换服务器别名
38
+ let serverQueryName = serverNameAlias[serverName]
39
+ if (!serverQueryName) {
40
+ return '请输入正确的服务器名称 (s1, s2, p, a)'
41
+ }
42
+
43
+ let trafficData = await truckyAppApi.trafficTop(ctx.http, serverQueryName)
44
+ if (trafficData.error) {
45
+ return '查询路况信息失败'
46
+ }
47
+
48
+ // 构建消息
49
+ let message = ''
50
+ for (const traffic of trafficData.data) {
51
+ // 如果已有内容,换行
52
+ if (message) {
53
+ message += '\n\n'
54
+ }
55
+
56
+ message += await baiduTranslate(ctx, cfg, traffic.country)
57
+ message += ' - '
58
+ let name = traffic.name.substring(0, traffic.name.lastIndexOf('(') - 1)
59
+ let type = traffic.name.substring(traffic.name.lastIndexOf('(') + 1, traffic.name.lastIndexOf(')'))
60
+ message += await baiduTranslate(ctx, cfg, name) + ` (${typeToZh[type] || type})`
61
+ message += '\n路况: ' + (severityToZh[traffic.newSeverity] || traffic.color)
62
+ message += ' | 人数: ' + traffic.players
63
+ }
64
+
65
+ return message
66
+ }
@@ -0,0 +1,16 @@
1
+ const truckersMpApi = require("../api/truckersMpApi");
2
+
3
+ module.exports = async (ctx) => {
4
+ // 查询版本信息
5
+ let result = await truckersMpApi.version(ctx.http)
6
+ if (result.error) {
7
+ return '查询失败,请稍后再试'
8
+ }
9
+
10
+ // 构建消息返回
11
+ let message = ''
12
+ message += `TMP版本:${result.data.name}\n`;
13
+ message += `欧卡支持版本: ${result.data.supported_game_version}\n`;
14
+ message += `美卡支持版本: ${result.data.supported_ats_game_version}`;
15
+ return message
16
+ }
@@ -0,0 +1,42 @@
1
+ module.exports = {
2
+ /**
3
+ * 获取绑定信息
4
+ * @param db 数据源
5
+ * @param platform 平台
6
+ * @param userId 用户编号
7
+ */
8
+ async get (db, platform, userId) {
9
+ const guildBindList = await db.get('tmp_guild_bind', {
10
+ platform,
11
+ user_id: userId
12
+ })
13
+
14
+ if (guildBindList && guildBindList.length > 0) {
15
+ return guildBindList[0]
16
+ }
17
+
18
+ return null
19
+ },
20
+ /**
21
+ * 新增或更新绑定信息
22
+ * @param db 数据源
23
+ * @param platform 平台
24
+ * @param userId 用户编号
25
+ * @param tmpId TMP ID
26
+ */
27
+ saveOrUpdate (db, platform, userId, tmpId) {
28
+ this.get(db, platform, userId).then((data) => {
29
+ if (data) {
30
+ db.set('tmp_guild_bind', data.id, {
31
+ tmp_id: tmpId
32
+ })
33
+ } else {
34
+ db.create('tmp_guild_bind', {
35
+ platform: platform,
36
+ user_id: userId,
37
+ tmp_id: tmpId
38
+ })
39
+ }
40
+ })
41
+ }
42
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 数据表声明
3
+ */
4
+ const modelArray = {
5
+ tmp_guild_bind: {
6
+ id: {
7
+ type: 'unsigned',
8
+ length: 10,
9
+ nullable: false,
10
+ comment: '主键'
11
+ },
12
+ platform: {
13
+ type: 'string',
14
+ length: 50,
15
+ nullable: false,
16
+ comment: '所属平台'
17
+ },
18
+ user_id: {
19
+ type: 'string',
20
+ length: 50,
21
+ nullable: false,
22
+ comment: '用户编号'
23
+ },
24
+ tmp_id: {
25
+ type: 'unsigned',
26
+ length: 50,
27
+ nullable: false,
28
+ comment: 'TMP ID'
29
+ }
30
+ },
31
+ tmp_translate_cache: {
32
+ id: {
33
+ type: 'unsigned',
34
+ length: 10,
35
+ nullable: false,
36
+ comment: '主键'
37
+ },
38
+ content: {
39
+ type: 'string',
40
+ nullable: false,
41
+ length: 200,
42
+ comment: '原文文本'
43
+ },
44
+ content_md5: {
45
+ type: 'string',
46
+ nullable: false,
47
+ length: 32,
48
+ comment: '原文文本md5'
49
+ },
50
+ translate_content: {
51
+ type: 'string',
52
+ nullable: false,
53
+ length: 200,
54
+ comment: '翻译文本'
55
+ }
56
+ }
57
+ }
58
+
59
+ /**
60
+ * 初始化数据库
61
+ */
62
+ module.exports = (ctx) => {
63
+ for (let modelName in modelArray) {
64
+ ctx.model.extend(modelName, modelArray[modelName], { autoInc: true })
65
+ }
66
+ }
@@ -0,0 +1,33 @@
1
+ module.exports = {
2
+ /**
3
+ * 查询翻译
4
+ * @param db 数据源
5
+ * @param contentMd5 文本MD5
6
+ */
7
+ async getTranslate (db, contentMd5) {
8
+ const translateCacheList = await db.get('tmp_translate_cache', {
9
+ content_md5: contentMd5
10
+ })
11
+
12
+ // 如果查询到了缓存,直接返回翻译文本
13
+ if (translateCacheList && translateCacheList.length > 0) {
14
+ return translateCacheList[0].translate_content
15
+ }
16
+
17
+ return null
18
+ },
19
+ /**
20
+ * 保存翻译缓存信息
21
+ * @param db 数据源
22
+ * @param contentMd5 原文文本MD5
23
+ * @param content 原文文本
24
+ * @param translateContent 翻译文本
25
+ */
26
+ save (db, contentMd5, content, translateContent) {
27
+ db.create('tmp_translate_cache', {
28
+ content,
29
+ content_md5: contentMd5,
30
+ translate_content: translateContent
31
+ })
32
+ }
33
+ }
@@ -0,0 +1,37 @@
1
+ const md5 = require('js-md5')
2
+ const translateCache = require('../database/translateCache')
3
+ const TRANSLATE_API = 'https://fanyi-api.baidu.com/api/trans/vip/translate'
4
+
5
+ module.exports = async (ctx, cfg, content, cache = true) => {
6
+ // 没有开启百度翻译功能,直接返回文本
7
+ if (!cfg.baiduTranslateEnable) {
8
+ return content
9
+ }
10
+
11
+ // 如果开启了缓存,尝试从缓存中查询翻译
12
+ if (cfg.baiduTranslateCacheEnable && cache) {
13
+ let translateContent = await translateCache.getTranslate(ctx.database, md5(content))
14
+ if (translateContent) {
15
+ return translateContent
16
+ }
17
+ }
18
+
19
+ // 创建请求秘钥
20
+ let randomInt = Math.floor(Math.random() * 10000)
21
+ let sign = md5(cfg.baiduTranslateAppId + content + randomInt + cfg.baiduTranslateKey)
22
+
23
+ // 调用请求
24
+ let result = await ctx.http.get(`${TRANSLATE_API}?q=${encodeURI(content)}&from=auto&to=zh&appid=${cfg.baiduTranslateAppId}&salt=${randomInt}&sign=${sign}`);
25
+
26
+ // 如果翻译失败,直接返回内容
27
+ if (result.error_code) {
28
+ return content
29
+ }
30
+
31
+ // 如果开启了缓存,将翻译内容缓存到数据库
32
+ if (cfg.baiduTranslateCacheEnable && cache) {
33
+ translateCache.save(ctx.database, md5(content), content, result.trans_result[0].dst)
34
+ }
35
+
36
+ return result.trans_result[0].dst
37
+ }
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ sleep (ms) {
3
+ return new Promise(resolve => setTimeout(resolve, ms));
4
+ }
5
+ }
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+ /**
3
+ * 路况信息展示方式
4
+ */
5
+ TmpTrafficType: {
6
+ text: 1, // 文本
7
+ heatMap: 2, // 热力图
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-tmp-bot",
3
3
  "description": "欧洲卡车模拟2 TMP查询插件,不会部署的可以直接使用此机器人->QQ:3523283907",
4
- "version": "1.16.0",
4
+ "version": "1.16.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "homepage": "https://github.com/79887143/koishi-plugin-tmp-bot",
@@ -28,10 +28,10 @@
28
28
  }
29
29
  },
30
30
  "peerDependencies": {
31
- "koishi": "^4.17.1"
31
+ "koishi": "^4.18.7"
32
32
  },
33
33
  "dependencies": {
34
- "dayjs": "^1.11.10",
34
+ "dayjs": "^1.11.13",
35
35
  "js-md5": "^0.8.3"
36
36
  }
37
37
  }