koishi-plugin-ets2-tools-tmp 3.3.3 → 3.3.5
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/api/evmOpenApi.js
CHANGED
|
@@ -223,4 +223,34 @@ module.exports = {
|
|
|
223
223
|
}
|
|
224
224
|
return data
|
|
225
225
|
},
|
|
226
|
+
/**
|
|
227
|
+
* 查询 Steam 游戏时长(ETS2 227300 / ATS 270880)
|
|
228
|
+
* 通过代理访问 Steam IPlayerService,返回格式化后的 { ets2, ats } 字符串
|
|
229
|
+
* 未配置 apiKey 或请求失败时对应字段为 null
|
|
230
|
+
*/
|
|
231
|
+
async steamGameTime(http, steamApiKey, steamId) {
|
|
232
|
+
if (!steamApiKey || !steamId) {
|
|
233
|
+
return { ets2: null, ats: null }
|
|
234
|
+
}
|
|
235
|
+
const path = `/proxy/steam/IPlayerService/GetOwnedGames/v1?key=${encodeURIComponent(steamApiKey)}&steamid=${steamId}&appids_filter[0]=227300&appids_filter[1]=270880&include_played_free_games=1`
|
|
236
|
+
let response
|
|
237
|
+
try {
|
|
238
|
+
response = await apiLog.get(http, 'evm.steam.gameTime', `${BASE_APIS[0]}${path}`)
|
|
239
|
+
} catch {
|
|
240
|
+
return { ets2: null, ats: null }
|
|
241
|
+
}
|
|
242
|
+
const result = { ets2: null, ats: null }
|
|
243
|
+
if (response?.response?.game_count > 0 && Array.isArray(response.response.games)) {
|
|
244
|
+
for (const game of response.response.games) {
|
|
245
|
+
const minutes = game.playtime_forever
|
|
246
|
+
if (minutes == null) continue
|
|
247
|
+
const h = Math.floor(minutes / 60)
|
|
248
|
+
const m = minutes % 60
|
|
249
|
+
const playtime = `${h}小时${m}分钟`
|
|
250
|
+
if (game.appid === 227300) result.ets2 = playtime
|
|
251
|
+
else if (game.appid === 270880) result.ats = playtime
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return result
|
|
255
|
+
},
|
|
226
256
|
}
|
|
@@ -161,28 +161,12 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
161
161
|
data.ets2GameTime = null;
|
|
162
162
|
data.atsGameTime = null;
|
|
163
163
|
if (cfg.commands?.tmpQueryGameTime) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (response.response && response.response.game_count > 0) {
|
|
171
|
-
for (const game of response.response.games) {
|
|
172
|
-
const playtimeMinutes = game.playtime_forever;
|
|
173
|
-
const hours = Math.floor(playtimeMinutes / 60);
|
|
174
|
-
const minutes = playtimeMinutes % 60;
|
|
175
|
-
const playtime = `${hours}小时${minutes}分钟`;
|
|
176
|
-
if (game.appid === 227300) {
|
|
177
|
-
data.ets2GameTime = playtime;
|
|
178
|
-
} else if (game.appid === 270880) {
|
|
179
|
-
data.atsGameTime = playtime;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
} catch (error) {
|
|
185
|
-
ctx.logger.error(`查询Steam游戏时长出错: ${error}`);
|
|
164
|
+
const steamApiKey = cfg.steamApi?.key;
|
|
165
|
+
if (steamApiKey) {
|
|
166
|
+
const steamId = playerInfo.data.steamId;
|
|
167
|
+
const gameTimes = await evmOpenApi.steamGameTime(ctx.http, steamApiKey, steamId);
|
|
168
|
+
data.ets2GameTime = gameTimes.ets2;
|
|
169
|
+
data.atsGameTime = gameTimes.ats;
|
|
186
170
|
}
|
|
187
171
|
}
|
|
188
172
|
let page;
|
|
@@ -184,35 +184,11 @@ module.exports = async (ctx, cfg, session, tmpId) => {
|
|
|
184
184
|
|
|
185
185
|
// 查询Steam游戏时长
|
|
186
186
|
async function getSteamGameTimes(steamId) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (!steamApiKey) {
|
|
190
|
-
return { ets2: null, ats: null };
|
|
191
|
-
}
|
|
192
|
-
const url = `https://evmapi.cxnnn.cn/proxy/steam/IPlayerService/GetOwnedGames/v1?key=${steamApiKey}&steamid=${steamId}&appids_filter[0]=227300&appids_filter[1]=270880&include_played_free_games=1`;
|
|
193
|
-
const response = await ctx.http.get(url);
|
|
194
|
-
const result = { ets2: null, ats: null };
|
|
195
|
-
|
|
196
|
-
if (response.response && response.response.game_count > 0) {
|
|
197
|
-
for (const game of response.response.games) {
|
|
198
|
-
const playtimeMinutes = game.playtime_forever;
|
|
199
|
-
const hours = Math.floor(playtimeMinutes / 60);
|
|
200
|
-
const minutes = playtimeMinutes % 60;
|
|
201
|
-
const playtime = `${hours}小时${minutes}分钟`;
|
|
202
|
-
|
|
203
|
-
if (game.appid === 227300) {
|
|
204
|
-
result.ets2 = playtime;
|
|
205
|
-
} else if (game.appid === 270880) {
|
|
206
|
-
result.ats = playtime;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return result;
|
|
212
|
-
} catch (error) {
|
|
213
|
-
ctx.logger.error(`查询Steam游戏时长出错: ${error}`);
|
|
187
|
+
const steamApiKey = cfg.steamApi?.key;
|
|
188
|
+
if (!steamApiKey) {
|
|
214
189
|
return { ets2: null, ats: null };
|
|
215
190
|
}
|
|
191
|
+
return evmOpenApi.steamGameTime(ctx.http, steamApiKey, steamId);
|
|
216
192
|
}
|
|
217
193
|
|
|
218
194
|
// 获取欧卡和美卡游戏时长
|
package/lib/util/apiLog.js
CHANGED
|
@@ -4,6 +4,35 @@
|
|
|
4
4
|
let logger = null
|
|
5
5
|
let debugMode = false
|
|
6
6
|
|
|
7
|
+
// 从异常对象中尽可能提取错误信息(错误名、消息、HTTP 状态码、错误码、底层原因、响应体)
|
|
8
|
+
// 仅用 e.message 时,网络层异常可能只有空消息(如只显示 "Error"),需补充状态码等上下文
|
|
9
|
+
function formatError(e) {
|
|
10
|
+
if (e == null) return '未知错误'
|
|
11
|
+
const parts = []
|
|
12
|
+
if (e.name && e.name !== 'Error') parts.push(e.name)
|
|
13
|
+
if (e.message) parts.push(e.message)
|
|
14
|
+
if (e.response && e.response.status != null) {
|
|
15
|
+
parts.push(`HTTP ${e.response.status}${e.response.statusText ? ` ${e.response.statusText}` : ''}`)
|
|
16
|
+
} else if (e.status != null) {
|
|
17
|
+
parts.push(`HTTP ${e.status}`)
|
|
18
|
+
}
|
|
19
|
+
if (e.code != null && e.code !== e.status && e.code !== e.response?.status) parts.push(`code=${e.code}`)
|
|
20
|
+
if (e.cause) parts.push(`cause=${e.cause.message || e.cause.code || String(e.cause)}`)
|
|
21
|
+
// 响应体中的错误信息(如网关返回的 JSON 错误内容)
|
|
22
|
+
const body = e.response && e.response.data
|
|
23
|
+
if (body != null) {
|
|
24
|
+
const text = typeof body === 'string' ? body : JSON.stringify(body)
|
|
25
|
+
if (text) parts.push(`响应体: ${text.slice(0, 300)}`)
|
|
26
|
+
}
|
|
27
|
+
if (!parts.length) {
|
|
28
|
+
// 兜底:枚举异常对象上的自定义属性(Error 标准属性不可枚举)
|
|
29
|
+
const props = {}
|
|
30
|
+
for (const key of Object.keys(e)) props[key] = e[key]
|
|
31
|
+
parts.push(Object.keys(props).length ? JSON.stringify(props) : String(e))
|
|
32
|
+
}
|
|
33
|
+
return parts.join(' | ')
|
|
34
|
+
}
|
|
35
|
+
|
|
7
36
|
module.exports = {
|
|
8
37
|
/**
|
|
9
38
|
* 初始化(在插件 apply 时调用)
|
|
@@ -29,7 +58,11 @@ module.exports = {
|
|
|
29
58
|
}
|
|
30
59
|
},
|
|
31
60
|
/**
|
|
32
|
-
*
|
|
61
|
+
* 格式化异常信息(提取错误名、HTTP 状态码、错误码、底层原因等),供其他模块复用
|
|
62
|
+
*/
|
|
63
|
+
formatError,
|
|
64
|
+
/**
|
|
65
|
+
* 发起 GET 请求并记录日志,失败时记录含错误码等详细信息的错误日志后抛出异常(由调用方原有 catch 处理)
|
|
33
66
|
*/
|
|
34
67
|
async get(http, tag, url) {
|
|
35
68
|
if (debugMode && logger) {
|
|
@@ -44,7 +77,11 @@ module.exports = {
|
|
|
44
77
|
return result
|
|
45
78
|
} catch (e) {
|
|
46
79
|
if (logger) {
|
|
47
|
-
logger.error(`[TMP-BOT API] [${tag}] 请求失败: ${url} (${e
|
|
80
|
+
logger.error(`[TMP-BOT API] [${tag}] 请求失败: ${url} (${formatError(e)})`)
|
|
81
|
+
// 调试模式下输出堆栈,便于定位异常来源
|
|
82
|
+
if (debugMode && e && e.stack) {
|
|
83
|
+
logger.error(`[TMP-BOT API] [${tag}] 堆栈: ${e.stack}`)
|
|
84
|
+
}
|
|
48
85
|
}
|
|
49
86
|
throw e
|
|
50
87
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const md5 = require('js-md5');
|
|
2
2
|
const translateCache = require('../database/translateCache');
|
|
3
|
+
const apiLog = require('./apiLog');
|
|
3
4
|
const TRANSLATE_API = 'https://fanyi-api.baidu.com/api/trans/vip/translate';
|
|
4
5
|
module.exports = async (ctx, cfg, content, cache = true) => {
|
|
5
6
|
if (!cfg.baiduTranslate.enable) {
|
|
@@ -18,7 +19,7 @@ module.exports = async (ctx, cfg, content, cache = true) => {
|
|
|
18
19
|
result = await ctx.http.get(`${TRANSLATE_API}?q=${encodeURI(content)}&from=auto&to=zh&appid=${cfg.baiduTranslate.appId}&salt=${randomInt}&sign=${sign}`);
|
|
19
20
|
} catch (error) {
|
|
20
21
|
// 翻译失败时降级返回原文,不影响主流程
|
|
21
|
-
ctx.logger.error(`[TMP-BOT] 百度翻译请求失败: ${
|
|
22
|
+
ctx.logger.error(`[TMP-BOT] 百度翻译请求失败: ${apiLog.formatError(error)}`);
|
|
22
23
|
return content;
|
|
23
24
|
}
|
|
24
25
|
if (result.error_code) {
|