koishi-plugin-ets2-tools-tmp 1.1.0 → 1.1.2
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 +75 -24
- package/package.json +1 -1
- package/readme.md +54 -47
package/lib/index.js
CHANGED
|
@@ -300,13 +300,15 @@ class ActivityService {
|
|
|
300
300
|
const previousActivityCount = this.todayActivities.length;
|
|
301
301
|
const previousTMPCount = this.todayTMPEvents.length;
|
|
302
302
|
const previousReminderCount = this.sentReminders.size;
|
|
303
|
-
|
|
304
303
|
this.todayActivities = [];
|
|
305
304
|
this.todayTMPEvents = [];
|
|
306
305
|
this.sentReminders.clear();
|
|
307
|
-
|
|
308
|
-
this.
|
|
309
|
-
|
|
306
|
+
this.logger.info(`[数据重置] 每日数据已重置: 活动${previousActivityCount}→0, TMP${previousTMPCount}→0, 提醒${previousReminderCount}→0`);
|
|
307
|
+
this.updateActivityData().then(() => {
|
|
308
|
+
this.logger.info(`[数据重置] 重置后数据更新完成: 活动${this.todayActivities.length}个, TMP${this.todayTMPEvents.length}个`);
|
|
309
|
+
}).catch(error => {
|
|
310
|
+
this.logger.error(`[数据重置] 重置后数据更新失败:`, error.message);
|
|
311
|
+
});
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
async updateActivityData() {
|
|
@@ -328,6 +330,8 @@ class ActivityService {
|
|
|
328
330
|
|
|
329
331
|
async updateTodayActivities() {
|
|
330
332
|
try {
|
|
333
|
+
this.todayActivities = [];
|
|
334
|
+
|
|
331
335
|
const protocol = this.cfg.adminUseHttps ? "https://" : "http://";
|
|
332
336
|
const fullUrl = `${protocol}${this.cfg.adminApiUrl}/api/activity/info/list?token=${this.cfg.adminApiToken}&page=1&limit=50&themeName=`;
|
|
333
337
|
this.logger.api(`请求车队平台API: ${fullUrl.replace(this.cfg.adminApiToken, "***")}`);
|
|
@@ -347,53 +351,88 @@ class ActivityService {
|
|
|
347
351
|
|
|
348
352
|
if (response.code === 0 && response.data?.list) {
|
|
349
353
|
const today = new Date().toISOString().split("T")[0];
|
|
354
|
+
this.logger.debug(`[活动更新] 当前日期: ${today}`);
|
|
355
|
+
|
|
350
356
|
const originalCount = response.data.list.length;
|
|
357
|
+
this.logger.debug(`[活动更新] API返回活动总数: ${originalCount}`);
|
|
358
|
+
if (this.cfg.debugMode && originalCount > 0) {
|
|
359
|
+
const activityDates = response.data.list.map(a => `${a.themeName}: ${a.startTime?.split(" ")[0]}`);
|
|
360
|
+
this.logger.debug(`[活动更新] 所有活动日期:`, activityDates);
|
|
361
|
+
}
|
|
362
|
+
|
|
351
363
|
this.todayActivities = response.data.list.filter((activity) => {
|
|
352
364
|
const activityDate = activity.startTime?.split(" ")[0];
|
|
353
|
-
|
|
365
|
+
const isToday = activityDate === today;
|
|
366
|
+
if (!isToday && this.cfg.debugMode) {
|
|
367
|
+
this.logger.debug(`[活动更新] 跳过非今日活动: ${activity.themeName}, 日期: ${activityDate}`);
|
|
368
|
+
}
|
|
369
|
+
return isToday;
|
|
354
370
|
});
|
|
355
|
-
|
|
371
|
+
|
|
372
|
+
this.logger.info(`[活动更新] 从车队平台找到 ${this.todayActivities.length}/${originalCount} 个今日活动`);
|
|
373
|
+
if (this.cfg.debugMode && this.todayActivities.length > 0) {
|
|
374
|
+
const todayActivityNames = this.todayActivities.map(a => `${a.themeName}: ${a.startTime}`);
|
|
375
|
+
this.logger.debug(`[活动更新] 今日活动详情:`, todayActivityNames);
|
|
376
|
+
}
|
|
356
377
|
} else {
|
|
357
|
-
this.logger.error(
|
|
378
|
+
this.logger.error(`[活动更新] 车队平台API返回错误: ${response.msg || '未知错误'} (代码: ${response.code || '无'})`);
|
|
358
379
|
this.todayActivities = [];
|
|
359
380
|
}
|
|
360
381
|
} catch (error) {
|
|
361
|
-
this.logger.error("获取车队平台活动列表失败:", error.message);
|
|
382
|
+
this.logger.error("[活动更新] 获取车队平台活动列表失败:", error.message);
|
|
362
383
|
this.todayActivities = [];
|
|
363
384
|
}
|
|
364
385
|
}
|
|
365
386
|
|
|
366
387
|
async updateTodayTMPEvents() {
|
|
367
388
|
try {
|
|
389
|
+
this.todayTMPEvents = [];
|
|
390
|
+
|
|
368
391
|
if (!this.cfg.adminVtcId) {
|
|
369
|
-
this.logger.warn("TMP API请求失败:未配置adminVtcId");
|
|
370
|
-
this.todayTMPEvents = [];
|
|
392
|
+
this.logger.warn("[TMP活动更新] TMP API请求失败:未配置adminVtcId");
|
|
371
393
|
return;
|
|
372
394
|
}
|
|
373
395
|
|
|
374
396
|
const tmpApiUrl = `https://api.truckersmp.com/v2/vtc/${this.cfg.adminVtcId}/events/attending/`;
|
|
375
|
-
this.logger.api(
|
|
397
|
+
this.logger.api(`[TMP活动更新] 请求TMP API: ${tmpApiUrl}`);
|
|
376
398
|
|
|
377
399
|
const startTime = Date.now();
|
|
378
400
|
const response = await this.ctx.http.get(tmpApiUrl, { timeout: 10000 });
|
|
379
401
|
const duration = Date.now() - startTime;
|
|
380
|
-
this.logger.api(`TMP API响应耗时: ${duration}ms, 错误状态: ${response.error}`);
|
|
402
|
+
this.logger.api(`[TMP活动更新] TMP API响应耗时: ${duration}ms, 错误状态: ${response.error}`);
|
|
381
403
|
|
|
382
404
|
if (!response.error && Array.isArray(response.response)) {
|
|
383
405
|
const today = new Date().toISOString().split("T")[0];
|
|
406
|
+
this.logger.debug(`[TMP活动更新] 当前日期: ${today}`);
|
|
407
|
+
|
|
384
408
|
const originalCount = response.response.length;
|
|
409
|
+
this.logger.debug(`[TMP活动更新] API返回活动总数: ${originalCount}`);
|
|
410
|
+
|
|
411
|
+
if (this.cfg.debugMode && originalCount > 0) {
|
|
412
|
+
const eventDates = response.response.map(e => `${e.name}: ${e.start_at?.split(" ")[0]}`);
|
|
413
|
+
this.logger.debug(`[TMP活动更新] 所有活动日期:`, eventDates);
|
|
414
|
+
}
|
|
415
|
+
|
|
385
416
|
this.todayTMPEvents = response.response.filter((event) => {
|
|
386
417
|
const eventDate = event.start_at?.split(" ")[0];
|
|
387
|
-
|
|
418
|
+
const isToday = eventDate === today;
|
|
419
|
+
if (!isToday && this.cfg.debugMode) {
|
|
420
|
+
this.logger.debug(`[TMP活动更新] 跳过非今日活动: ${event.name}, 日期: ${eventDate}`);
|
|
421
|
+
}
|
|
422
|
+
return isToday;
|
|
388
423
|
});
|
|
389
|
-
|
|
424
|
+
|
|
425
|
+
this.logger.info(`[TMP活动更新] 从TMP找到 ${this.todayTMPEvents.length}/${originalCount} 个今日活动`);
|
|
426
|
+
|
|
427
|
+
if (this.cfg.debugMode && this.todayTMPEvents.length > 0) {
|
|
428
|
+
const todayEventNames = this.todayTMPEvents.map(e => `${e.name}: ${e.start_at}`);
|
|
429
|
+
this.logger.debug(`[TMP活动更新] 今日活动详情:`, todayEventNames);
|
|
430
|
+
}
|
|
390
431
|
} else {
|
|
391
|
-
this.logger.error(`TMP API返回错误: ${response.message || '未知错误'}`);
|
|
392
|
-
this.todayTMPEvents = [];
|
|
432
|
+
this.logger.error(`[TMP活动更新] TMP API返回错误: ${response.message || '未知错误'}`);
|
|
393
433
|
}
|
|
394
434
|
} catch (error) {
|
|
395
|
-
this.logger.error("获取TMP活动失败:", error.message);
|
|
396
|
-
this.todayTMPEvents = [];
|
|
435
|
+
this.logger.error("[TMP活动更新] 获取TMP活动失败:", error.message);
|
|
397
436
|
}
|
|
398
437
|
}
|
|
399
438
|
|
|
@@ -424,11 +463,18 @@ class ActivityService {
|
|
|
424
463
|
|
|
425
464
|
async checkAndSendActivityReminders() {
|
|
426
465
|
const now = new Date();
|
|
466
|
+
const today = now.toISOString().split("T")[0];
|
|
427
467
|
let remindersSent = 0;
|
|
428
|
-
this.logger.debug(`检查 ${this.todayActivities.length}
|
|
468
|
+
this.logger.debug(`检查 ${this.todayActivities.length} 个活动的提醒时间,当前日期: ${today}`);
|
|
429
469
|
|
|
430
470
|
for (const activity of this.todayActivities) {
|
|
431
471
|
try {
|
|
472
|
+
const activityDate = activity.startTime?.split(" ")[0];
|
|
473
|
+
if (activityDate !== today) {
|
|
474
|
+
this.logger.debug(`跳过非今日活动 "${activity.themeName}",活动日期: ${activityDate},当前日期: ${today}`);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
|
|
432
478
|
const activityStartTime = new Date(activity.startTime);
|
|
433
479
|
if (isNaN(activityStartTime.getTime())) {
|
|
434
480
|
this.logger.warn(`活动 "${activity.themeName}" 开始时间格式错误,跳过提醒`);
|
|
@@ -436,10 +482,13 @@ class ActivityService {
|
|
|
436
482
|
}
|
|
437
483
|
|
|
438
484
|
const timeDiff = activityStartTime.getTime() - now.getTime();
|
|
439
|
-
const
|
|
440
|
-
|
|
485
|
+
const totalSecondsLeft = Math.floor(timeDiff / 1000);
|
|
486
|
+
const minutesLeft = Math.floor(totalSecondsLeft / 60);
|
|
487
|
+
const secondsLeft = totalSecondsLeft % 60;
|
|
488
|
+
this.logger.debug(`活动 "${activity.themeName}" 剩余时间: ${minutesLeft} 分 ${secondsLeft} 秒`);
|
|
441
489
|
|
|
442
|
-
|
|
490
|
+
// 活动开始提醒:只在活动开始时间点触发(允许30秒误差)
|
|
491
|
+
if (totalSecondsLeft >= -30 && totalSecondsLeft <= 0) {
|
|
443
492
|
const startReminderKey = `${activity.id}_started`;
|
|
444
493
|
if (!this.sentReminders.has(startReminderKey)) {
|
|
445
494
|
this.logger.debug(`触发活动开始提醒: ${activity.themeName}`);
|
|
@@ -449,9 +498,11 @@ class ActivityService {
|
|
|
449
498
|
}
|
|
450
499
|
}
|
|
451
500
|
|
|
452
|
-
|
|
501
|
+
// 活动前提醒:只在精确时间点触发(允许30秒误差)
|
|
502
|
+
if (totalSecondsLeft < 0) continue;
|
|
453
503
|
for (const reminderTime of this.cfg.mainActivityReminderTimes) {
|
|
454
|
-
|
|
504
|
+
const reminderTimeSeconds = reminderTime * 60;
|
|
505
|
+
if (totalSecondsLeft <= reminderTimeSeconds && totalSecondsLeft > reminderTimeSeconds - 30) {
|
|
455
506
|
const reminderKey = `${activity.id}_${reminderTime}`;
|
|
456
507
|
if (!this.sentReminders.has(reminderKey)) {
|
|
457
508
|
this.logger.debug(`触发提醒: ${activity.themeName} - ${reminderTime} 分钟前`);
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -2,63 +2,63 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/koishi-plugin-tmp-bot)
|
|
4
4
|
|
|
5
|
-
## 插件介绍
|
|
5
|
+
## 🚛 插件介绍
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
一款专为欧洲卡车模拟2 (ETS2) / 美国卡车模拟 (ATS) 玩家打造的多功能插件,集成TMP数据查询与车队活动管理功能。支持自动获取活动信息、智能提醒推送,提供丰富的游戏数据查询服务,完美适配QQ等主流聊天平台。
|
|
8
8
|
|
|
9
|
-
## 功能特性
|
|
9
|
+
## ✨ 功能特性
|
|
10
10
|
|
|
11
11
|
### 🎮 核心查询功能
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- **VTC
|
|
12
|
+
- **玩家数据查询**:支持TMP玩家信息、实时位置查询,绑定ID后操作更便捷
|
|
13
|
+
- **服务器与路况**:查询欧卡/美卡服务器状态、热门地点路况(支持服务器简称速查)
|
|
14
|
+
- **游戏资源查询**:地图DLC价格、TMP版本信息一键获取
|
|
15
|
+
- **排行与积分**:总里程/今日里程排行榜、车队平台积分查询
|
|
16
|
+
- **VTC与规则**:支持指定VTC ID查询,提供TruckersMP官方规则快速链接
|
|
17
17
|
|
|
18
18
|
### 🚚 车队活动管理
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
19
|
+
- **双数据源支持**:同时对接车队平台(V1.0)和TruckersMP API获取活动数据
|
|
20
|
+
- **智能提醒机制**:活动开始前按配置时间自动发送提醒,支持多时间点精准设置
|
|
21
|
+
- **档位状态检查**:自动检测活动档上传状态,及时向管理群发送提醒
|
|
22
|
+
- **多群组适配**:区分管理群与主群,按需发送不同类型通知消息
|
|
23
23
|
|
|
24
24
|
### ⚙️ 灵活配置选项
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
25
|
+
- **数据源自定义**:独立选择服务器、起点、终点信息来源(车队平台/ TMP API)
|
|
26
|
+
- **定时任务配置**:自定义活动检查、消息发送的时间节点
|
|
27
|
+
- **消息模板编辑**:支持变量替换的个性化提醒模板,打造专属通知风格
|
|
28
|
+
- **权限与适配**:管理员专用功能(密码重置),兼容主流聊天平台
|
|
29
29
|
|
|
30
30
|
### 🔧 开发者支持
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
31
|
+
- **多级日志记录**:调试模式、API监控、定时任务记录等细分日志选项
|
|
32
|
+
- **详细调试信息**:插件运行状态、数据统计一键查看
|
|
33
|
+
- **接口文档支持**:提供TMP数据接口文档,便于二次开发扩展
|
|
34
34
|
|
|
35
|
-
## 安装配置
|
|
35
|
+
## 📦 安装配置
|
|
36
36
|
|
|
37
37
|
### 1. 基础配置
|
|
38
38
|
|
|
39
39
|
#### API配置
|
|
40
|
-
- **使用HTTPS
|
|
41
|
-
- **车队平台URL
|
|
42
|
-
- **车队平台TOKEN
|
|
43
|
-
- **VTC ID
|
|
40
|
+
- **使用HTTPS协议**:选择是否启用HTTPS协议
|
|
41
|
+
- **车队平台URL**:自行部署的车队平台地址(不含协议,仅支持V1.0版本)
|
|
42
|
+
- **车队平台TOKEN**:API访问认证令牌
|
|
43
|
+
- **VTC ID**:您在TruckersMP的VTC ID
|
|
44
44
|
|
|
45
45
|
#### 翻译配置(可选)
|
|
46
|
-
-
|
|
47
|
-
- **百度翻译APP ID
|
|
48
|
-
-
|
|
49
|
-
-
|
|
46
|
+
- **启用百度翻译**:开启/关闭翻译功能
|
|
47
|
+
- **百度翻译APP ID**:翻译服务认证ID
|
|
48
|
+
- **百度翻译秘钥**:翻译服务认证密钥
|
|
49
|
+
- **启用翻译缓存**:减少重复翻译请求,提升效率
|
|
50
50
|
|
|
51
51
|
### 2. 群组配置
|
|
52
52
|
|
|
53
53
|
#### 管理群设置
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
- **管理群组ID
|
|
54
|
+
- **活动检查时间**:检查活动档位状态的时间(HH:mm格式)
|
|
55
|
+
- **信息发送时间**:发送档位提醒的时间(HH:mm格式)
|
|
56
|
+
- **管理群组ID**:接收管理提醒(档位状态、异常通知)的群组ID列表
|
|
57
57
|
|
|
58
58
|
#### 主群设置
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
59
|
+
- **主群群号**:接收活动开始提醒的群组ID列表
|
|
60
|
+
- **活动提醒消息模板**:支持变量替换的自定义模板
|
|
61
|
+
- **活动提醒时间**:活动开始前的提醒时间点(分钟)
|
|
62
62
|
|
|
63
63
|
### 3. 数据源与消息配置
|
|
64
64
|
|
|
@@ -69,18 +69,25 @@
|
|
|
69
69
|
- 活动横幅显示开关
|
|
70
70
|
|
|
71
71
|
#### 消息内容配置
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
72
|
+
- **档位已上传消息**:活动档上传完成时的提示文案
|
|
73
|
+
- **档位未上传消息**:活动档未上传时的提醒文案
|
|
74
|
+
- **活动提醒模板变量**:
|
|
75
|
+
- `{name}`(活动名)
|
|
76
|
+
- `{server}`(服务器)
|
|
77
|
+
- `{startingPoint}`(起点)
|
|
78
|
+
- `{terminalPoint}`(终点)
|
|
79
|
+
- `{distance}`(距离)
|
|
80
|
+
- `{banner}`(横幅)
|
|
81
|
+
- `{timeLeft}`(剩余时间)
|
|
75
82
|
|
|
76
83
|
### 4. 开发者选项
|
|
77
|
-
-
|
|
78
|
-
- **记录API
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
84
|
+
- **调试模式**:启用后输出详细运行日志
|
|
85
|
+
- **记录API响应**:记录API请求参数与响应详情
|
|
86
|
+
- **记录定时任务**:记录定时任务执行时间、结果
|
|
87
|
+
- **记录活动匹配**:记录活动数据跨源匹配过程
|
|
88
|
+
- **记录消息发送**:记录消息发送状态、接收群组
|
|
82
89
|
|
|
83
|
-
## 指令说明
|
|
90
|
+
## 📋 指令说明
|
|
84
91
|
|
|
85
92
|
| 指令名称 | 指令介绍 | 使用示例 |
|
|
86
93
|
|------------------|---------------------------------------------------------------------------------------------------------------------------------------------|------------------------|
|
|
@@ -102,7 +109,7 @@
|
|
|
102
109
|
| 活动DEBUG | 查看插件运行状态、数据统计等调试信息 | 活动DEBUG |
|
|
103
110
|
| 重置数据 | 手动重置今日活动数据与提醒记录 | 重置数据 |
|
|
104
111
|
|
|
105
|
-
## 使用方法
|
|
112
|
+
## 📝 使用方法
|
|
106
113
|
|
|
107
114
|
### 自动功能
|
|
108
115
|
- 每日凌晨2点自动重置活动数据
|
|
@@ -113,9 +120,9 @@
|
|
|
113
120
|
### 注意事项
|
|
114
121
|
- 车队平台仅支持V1.0版本,V2.0版本适配将在后续更新
|
|
115
122
|
- 路况查询仅支持指定服务器简称,需按规则输入(s1/s2/p/a)
|
|
116
|
-
-
|
|
123
|
+
- 管理员专用功能(如重置密码)需提前配置管理员权限
|
|
117
124
|
|
|
118
|
-
## 技术支持
|
|
125
|
+
## 🔍 技术支持
|
|
119
126
|
|
|
120
127
|
### 接口文档
|
|
121
128
|
TMP数据接口文档:https://apifox.com/apidoc/shared/38508a88-5ff4-4b29-b724-41f9d3d3336a
|
|
@@ -126,7 +133,7 @@ TMP数据接口文档:https://apifox.com/apidoc/shared/38508a88-5ff4-4b29-b724
|
|
|
126
133
|
3. 确认群组ID格式正确,机器人拥有发送消息权限
|
|
127
134
|
4. 定时任务未执行可检查服务器时间与配置时间是否匹配
|
|
128
135
|
|
|
129
|
-
##
|
|
136
|
+
## 致谢
|
|
130
137
|
特别感谢 [79887143](https://github.com/79887143) 提供的API接口与开发思路,基于其开源项目 [koishi-plugin-tmp-bot](https://github.com/79887143/koishi-plugin-tmp-bot?tab=readme-ov-file#koishi-plugin-tmp-bot) 扩展开发。
|
|
131
138
|
|
|
132
139
|
## 版本信息
|