koishi-plugin-tmp-bot 1.0.0

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,50 @@
1
+ const BASE_API = 'https://api.truckersmp.com/v2'
2
+
3
+ module.exports = {
4
+ /**
5
+ * 查询玩家信息
6
+ */
7
+ async player (http, tmpId) {
8
+ let result = null
9
+ try {
10
+ result = await http.get(`${BASE_API}/player/${tmpId}`)
11
+ } catch {
12
+ return {
13
+ error: true
14
+ }
15
+ }
16
+
17
+ // 拼接返回数据
18
+ let data = {
19
+ error: JSON.parse(result.error)
20
+ }
21
+ if (!data.error) {
22
+ data.data = result.response
23
+ }
24
+
25
+ return data
26
+ },
27
+ /**
28
+ * 查询服务器列表
29
+ */
30
+ async servers (http) {
31
+ let result = null
32
+ try {
33
+ result = await http.get(`${BASE_API}/servers`)
34
+ } catch {
35
+ return {
36
+ error: true
37
+ }
38
+ }
39
+
40
+ // 拼接返回数据
41
+ let data = {
42
+ error: JSON.parse(result.error)
43
+ }
44
+ if (!data.error) {
45
+ data.data = result.response
46
+ }
47
+
48
+ return data
49
+ }
50
+ }
@@ -0,0 +1,26 @@
1
+ const BASE_API_V3 = 'https://api.truckyapp.com/v3'
2
+
3
+ module.exports = {
4
+ /**
5
+ * 查询线上信息
6
+ */
7
+ async online (http, tmpId) {
8
+ let result = null
9
+ try {
10
+ result = await http.get(`${BASE_API_V3}/map/online?playerID=${tmpId}`)
11
+ } catch {
12
+ return {
13
+ error: true
14
+ }
15
+ }
16
+
17
+ // 拼接返回数据
18
+ let data = {
19
+ error: !result || !result.response || result.response.error
20
+ }
21
+ if (!data.error) {
22
+ data.data = result.response
23
+ }
24
+ return data
25
+ }
26
+ }
@@ -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.guildId, session.userId, session.author.username, tmpId)
20
+
21
+ return `绑定成功 ( ${playerInfo.data.name} )`
22
+ }
@@ -0,0 +1,73 @@
1
+ const dayjs = require('dayjs')
2
+ const guildBind = require('../database/guildBind')
3
+ const truckersMpApi = require('../api/TruckersMpApi')
4
+ const truckyAppApi = require('../api/truckyAppApi')
5
+ const baiduTranslate = require('../util/baiduTranslate')
6
+
7
+ /**
8
+ * 用户组
9
+ */
10
+ const userGroup = {
11
+ 'Player': '玩家',
12
+ 'Retired Legend': '退役',
13
+ 'Game Developer': '游戏开发者'
14
+ }
15
+
16
+ /**
17
+ * 查询玩家信息
18
+ */
19
+ module.exports = async (ctx, cfg, session, tmpId) => {
20
+ if (tmpId && isNaN(tmpId)) {
21
+ return `请输入正确的玩家编号`
22
+ }
23
+
24
+ // 如果没有传入tmpId,尝试从数据库查询绑定信息
25
+ if (!tmpId) {
26
+ let guildBindData = await guildBind.get(ctx.database, session.platform, session.guildId, session.userId)
27
+ if (!guildBindData) {
28
+ return `请输入正确的玩家编号`
29
+ }
30
+ tmpId = guildBindData.tmp_id
31
+ }
32
+
33
+ // 查询玩家信息
34
+ let playerInfo = await truckersMpApi.player(ctx.http, tmpId)
35
+ if (playerInfo.error) {
36
+ return '查询玩家信息失败,请重试'
37
+ }
38
+
39
+ // 查询线上信息
40
+ let playerMapInfo = await truckyAppApi.online(ctx.http, tmpId)
41
+ if (playerMapInfo.error) {
42
+ return '查询玩家信息失败,请重试'
43
+ }
44
+
45
+ // 拼接消息模板 正常4763167 永久5396563 暂时封号5118166
46
+ let message = `<img src="${playerInfo.data.avatar}"/>`
47
+ message += '\n😀玩家名称: ' + playerInfo.data.name
48
+ message += '\n📑注册日期: ' + dayjs(playerInfo.data.joinDate + 'Z').format('YYYY年MM月DD日')
49
+ message += '\n💼所属分组: ' + (userGroup[playerInfo.data.groupName] || playerInfo.data.groupName) // 🪪💼📂🚹
50
+ if (playerInfo.data.vtc && playerInfo.data.vtc.inVTC) {
51
+ message += '\n🚚所属车队: ' + playerInfo.data.vtc.name
52
+ }
53
+ message += '\n🚫是否封禁: ' + (playerInfo.data.banned ? '是' : '否')
54
+ if (playerInfo.data.banned) {
55
+ message += '\n🚫封禁截止: '
56
+ if (!playerInfo.data.displayBans) {
57
+ message += '隐藏'
58
+ } else if (!playerInfo.data.bannedUntil) {
59
+ message += '永久'
60
+ } else {
61
+ message += daiyjs(playerInfo.data.bannedUntil + 'Z').format('YYYY年MM月DD日 HH:mm')
62
+ }
63
+ }
64
+ message += '\n🚫封禁次数: ' + playerInfo.data.bansCount || 0
65
+ message += '\n📶在线状态: ' + (playerMapInfo.data.online ? `在线🟢 (${playerMapInfo.data.serverDetails.name})` : '离线⚫')
66
+ if (playerMapInfo.data.online) {
67
+ message += '\n🌍线上位置: '
68
+ message += await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.country)
69
+ message += ' - '
70
+ message += await baiduTranslate(ctx, cfg, playerMapInfo.data.location.poi.realName)
71
+ }
72
+ return message
73
+ }
@@ -0,0 +1,39 @@
1
+ const truckersMpApi = require('../api/TruckersMpApi')
2
+
3
+ module.exports = async (ctx, cfg) => {
4
+ // 查询服务器信息
5
+ let serverData = await truckersMpApi.servers(ctx.http)
6
+ if (serverData.error) {
7
+ return '查询服务器失败,请稍后重试'
8
+ }
9
+
10
+ // 过滤非欧卡2服务器
11
+ let etsServerList = serverData.data.filter(server => server.game === 'ETS2')
12
+
13
+ // 构建消息
14
+ let message = ''
15
+ for (let server of etsServerList) {
16
+ // 如果前面有内容,换行
17
+ if (message) {
18
+ message += '\n\n'
19
+ }
20
+
21
+ message += '服务器: ' + ( server.online ? '🟢' : '⚫' ) + server.name
22
+ message += `\n玩家人数: ${server.players}/${server.maxplayers}`
23
+ if (server.queue) {
24
+ message += ` (队列: ${server.queue})`
25
+ }
26
+ // 服务器特性
27
+ let characteristicList = []
28
+ if (!server.afkenabled) {
29
+ characteristicList.push('⏱挂机')
30
+ }
31
+ if (server.collisions) {
32
+ characteristicList.push('💥碰撞')
33
+ }
34
+ if (characteristicList && characteristicList.length > 0) {
35
+ message += '\n服务器特性: ' + characteristicList.join(' ')
36
+ }
37
+ }
38
+ return message
39
+ }
@@ -0,0 +1,49 @@
1
+ module.exports = {
2
+ /**
3
+ * 获取绑定信息
4
+ * @param db 数据源
5
+ * @param platform 平台
6
+ * @param guildId 群组编号
7
+ * @param userId 用户编号
8
+ */
9
+ async get (db, platform, guildId, userId) {
10
+ const guildBindList = await db.get('tmp_guild_bind', {
11
+ platform,
12
+ guild_id: guildId,
13
+ user_id: userId
14
+ })
15
+
16
+ if (guildBindList && guildBindList.length > 0) {
17
+ return guildBindList[0]
18
+ }
19
+
20
+ return null
21
+ },
22
+ /**
23
+ * 新增或更新绑定信息
24
+ * @param db 数据源
25
+ * @param platform 平台
26
+ * @param guildId 群组编号
27
+ * @param userId 用户编号
28
+ * @param userName 用户昵称
29
+ * @param tmpId TMP ID
30
+ */
31
+ saveOrUpdate (db, platform, guildId, userId, userName, tmpId) {
32
+ this.get(db, platform, guildId, userId).then((data) => {
33
+ if (data) {
34
+ db.set('tmp_guild_bind', data.id, {
35
+ tmp_id: tmpId,
36
+ user_name: userName
37
+ })
38
+ } else {
39
+ db.create('tmp_guild_bind', {
40
+ platform: platform,
41
+ guild_id: guildId,
42
+ user_id: userId,
43
+ user_name: userName,
44
+ tmp_id: tmpId
45
+ })
46
+ }
47
+ })
48
+ }
49
+ }
@@ -0,0 +1,78 @@
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
+ guild_id: {
19
+ type: 'string',
20
+ length: 50,
21
+ nullable: false,
22
+ comment: '群组编号'
23
+ },
24
+ user_id: {
25
+ type: 'string',
26
+ length: 50,
27
+ nullable: false,
28
+ comment: '用户编号'
29
+ },
30
+ user_name: {
31
+ type: 'string',
32
+ length: 50,
33
+ nullable: false,
34
+ comment: '用户昵称'
35
+ },
36
+ tmp_id: {
37
+ type: 'unsigned',
38
+ length: 50,
39
+ nullable: false,
40
+ comment: 'TMP ID'
41
+ }
42
+ },
43
+ tmp_translate_cache: {
44
+ id: {
45
+ type: 'unsigned',
46
+ length: 10,
47
+ nullable: false,
48
+ comment: '主键'
49
+ },
50
+ content: {
51
+ type: 'string',
52
+ nullable: false,
53
+ length: 200,
54
+ comment: '原文文本'
55
+ },
56
+ content_md5: {
57
+ type: 'string',
58
+ nullable: false,
59
+ length: 32,
60
+ comment: '原文文本md5'
61
+ },
62
+ translate_content: {
63
+ type: 'string',
64
+ nullable: false,
65
+ length: 200,
66
+ comment: '翻译文本'
67
+ }
68
+ }
69
+ }
70
+
71
+ /**
72
+ * 初始化数据库
73
+ */
74
+ module.exports = (ctx) => {
75
+ for (let modelName in modelArray) {
76
+ ctx.model.extend(modelName, modelArray[modelName], { autoInc: true })
77
+ }
78
+ }
@@ -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
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Context, Schema } from 'koishi';
2
+ export declare const name = "tmp-bot";
3
+ export interface Config {
4
+ baiduTranslateEnable: boolean;
5
+ baiduTranslateAppId: string;
6
+ baiduTranslateKey: string;
7
+ baiduTranslateCacheEnable: boolean;
8
+ }
9
+ export declare const Config: Schema<Config>;
10
+ export declare function apply(ctx: Context, cfg: Config): void;
package/lib/index.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.apply = exports.Config = exports.name = void 0;
4
+ const koishi_1 = require("koishi");
5
+ const model = require('./database/model');
6
+ const tmpQuery = require('./command/tmpQuery');
7
+ const tmpServer = require('./command/tmpServer');
8
+ const tmpBind = require('./command/tmpBind');
9
+ exports.name = 'tmp-bot';
10
+ exports.Config = koishi_1.Schema.object({
11
+ baiduTranslateEnable: koishi_1.Schema.boolean().default(false).description('启用百度翻译'),
12
+ baiduTranslateAppId: koishi_1.Schema.string().description('百度翻译APP ID'),
13
+ baiduTranslateKey: koishi_1.Schema.string().description('百度翻译秘钥'),
14
+ baiduTranslateCacheEnable: koishi_1.Schema.boolean().default(false).description('启用百度翻译缓存')
15
+ });
16
+ function apply(ctx, cfg) {
17
+ // 注册指令
18
+ ctx.command('tmpquery <tmpId>').action(async ({ session }, tmpId) => await tmpQuery(ctx, cfg, session, tmpId));
19
+ ctx.command('tmpserver').action(async () => await tmpServer(ctx, cfg));
20
+ ctx.command('tmpbind <tmpId>').action(async ({ session }, tmpId) => await tmpBind(ctx, cfg, session, tmpId));
21
+ // 等待数据库模块准备完毕后初始化数据库表
22
+ let databaseTime = setInterval(() => {
23
+ if (ctx.database) {
24
+ clearInterval(databaseTime);
25
+ databaseTime = null;
26
+ model(ctx);
27
+ }
28
+ }, 100);
29
+ }
30
+ exports.apply = apply;
@@ -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) => {
6
+ // 没有开启百度翻译功能,直接返回文本
7
+ if (!cfg.baiduTranslateEnable) {
8
+ return content
9
+ }
10
+
11
+ // 如果开启了缓存,尝试从缓存中查询翻译
12
+ if (cfg.baiduTranslateCacheEnable) {
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) {
33
+ translateCache.save(ctx.database, md5(content), content, result.trans_result[0].dst)
34
+ }
35
+
36
+ return result.trans_result[0].dst
37
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "koishi-plugin-tmp-bot",
3
+ "description": "欧洲卡车模拟2 TMP查询机器人",
4
+ "version": "1.0.0",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "dist"
10
+ ],
11
+ "license": "MIT",
12
+ "scripts": {},
13
+ "keywords": [
14
+ "chatbot",
15
+ "koishi",
16
+ "plugin",
17
+ "truckersmp",
18
+ "gametool",
19
+ "ets2",
20
+ "tmp"
21
+ ],
22
+ "koishi": {
23
+ "service": {
24
+ "required": ["database"]
25
+ }
26
+ },
27
+ "peerDependencies": {
28
+ "koishi": "^4.17.1"
29
+ },
30
+ "dependencies": {
31
+ "dayjs": "^1.11.10",
32
+ "js-md5": "^0.8.3"
33
+ }
34
+ }
package/readme.md ADDED
@@ -0,0 +1,5 @@
1
+ # koishi-plugin-tmp-bot
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-tmp-bot?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-tmp-bot)
4
+
5
+ 欧洲卡车模拟2 TMP查询机器人