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.
- package/lib/api/TruckersMpApi.js +50 -0
- package/lib/api/truckyAppApi.js +26 -0
- package/lib/command/tmpBind.js +22 -0
- package/lib/command/tmpQuery.js +73 -0
- package/lib/command/tmpServer.js +39 -0
- package/lib/database/guildBind.js +49 -0
- package/lib/database/model.js +78 -0
- package/lib/database/translateCache.js +33 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +30 -0
- package/lib/util/baiduTranslate.js +37 -0
- package/package.json +34 -0
- package/readme.md +5 -0
|
@@ -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
|
+
}
|