koishi-plugin-video-parser-all 0.0.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.
- package/lib/index.d.ts +85 -0
- package/lib/index.js +281 -0
- package/package.json +39 -0
- package/readme.md +5 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Context, Schema } from 'koishi';
|
|
2
|
+
export declare const name = "video-parser";
|
|
3
|
+
export interface Config {
|
|
4
|
+
enable: boolean;
|
|
5
|
+
showWaitingTip: boolean;
|
|
6
|
+
waitingTipText: string;
|
|
7
|
+
parserSource: string;
|
|
8
|
+
returnComponents: string[];
|
|
9
|
+
allowBVAVParse: boolean;
|
|
10
|
+
sameLinkInterval: number;
|
|
11
|
+
minVideoDuration: number;
|
|
12
|
+
shortVideoTip: string;
|
|
13
|
+
shortVideoUseImageParse: boolean;
|
|
14
|
+
maxVideoDuration: number;
|
|
15
|
+
longVideoTip: string;
|
|
16
|
+
longVideoUseImageParse: boolean;
|
|
17
|
+
maxFileSize: number;
|
|
18
|
+
imageParseFormat: string;
|
|
19
|
+
showVideoLink: boolean;
|
|
20
|
+
maxDescLength: number;
|
|
21
|
+
enableMergeForward: boolean;
|
|
22
|
+
downloadBeforeSend: boolean;
|
|
23
|
+
messageBufferDelay: number;
|
|
24
|
+
userAgent: string;
|
|
25
|
+
publicApiKey: string;
|
|
26
|
+
bilibili: {
|
|
27
|
+
customApi: string;
|
|
28
|
+
apiKey: string;
|
|
29
|
+
fieldMap: {
|
|
30
|
+
title: string;
|
|
31
|
+
author: string;
|
|
32
|
+
description: string;
|
|
33
|
+
like: string;
|
|
34
|
+
coin: string;
|
|
35
|
+
collect: string;
|
|
36
|
+
share: string;
|
|
37
|
+
view: string;
|
|
38
|
+
danmaku: string;
|
|
39
|
+
cover: string;
|
|
40
|
+
duration: string;
|
|
41
|
+
size: string;
|
|
42
|
+
url: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
douyin: {
|
|
46
|
+
customApi: string;
|
|
47
|
+
apiKey: string;
|
|
48
|
+
fieldMap: {
|
|
49
|
+
title: string;
|
|
50
|
+
author: string;
|
|
51
|
+
description: string;
|
|
52
|
+
like: string;
|
|
53
|
+
coin: string;
|
|
54
|
+
collect: string;
|
|
55
|
+
share: string;
|
|
56
|
+
view: string;
|
|
57
|
+
danmaku: string;
|
|
58
|
+
cover: string;
|
|
59
|
+
duration: string;
|
|
60
|
+
size: string;
|
|
61
|
+
url: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
kuaishou: {
|
|
65
|
+
customApi: string;
|
|
66
|
+
apiKey: string;
|
|
67
|
+
fieldMap: {
|
|
68
|
+
title: string;
|
|
69
|
+
author: string;
|
|
70
|
+
description: string;
|
|
71
|
+
like: string;
|
|
72
|
+
coin: string;
|
|
73
|
+
collect: string;
|
|
74
|
+
share: string;
|
|
75
|
+
view: string;
|
|
76
|
+
danmaku: string;
|
|
77
|
+
cover: string;
|
|
78
|
+
duration: string;
|
|
79
|
+
size: string;
|
|
80
|
+
url: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export declare const Config: Schema<Config>;
|
|
85
|
+
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Config = exports.name = void 0;
|
|
7
|
+
exports.apply = apply;
|
|
8
|
+
const koishi_1 = require("koishi");
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
exports.name = 'video-parser';
|
|
12
|
+
// 简化 Schema 定义,避免类型冲突
|
|
13
|
+
exports.Config = koishi_1.Schema.object({
|
|
14
|
+
enable: koishi_1.Schema.boolean().default(true).description('开启解析功能'),
|
|
15
|
+
showWaitingTip: koishi_1.Schema.boolean().default(true).description('是否返回等待提示'),
|
|
16
|
+
waitingTipText: koishi_1.Schema.string().default('正在解析视频链接...可能需要稍等一下...').description('等待提示文字内容'),
|
|
17
|
+
parserSource: koishi_1.Schema.string().default('public').description('解析来源:public/自定义'),
|
|
18
|
+
returnComponents: koishi_1.Schema.array(String).default(['title', 'author', 'cover']).description('返回内容组件'),
|
|
19
|
+
allowBVAVParse: koishi_1.Schema.boolean().default(true).description('允许BV/AV号解析'),
|
|
20
|
+
sameLinkInterval: koishi_1.Schema.number().default(180).description('相同链接处理间隔(秒)'),
|
|
21
|
+
minVideoDuration: koishi_1.Schema.number().default(0).description('最小时长(分钟)'),
|
|
22
|
+
shortVideoTip: koishi_1.Schema.string().default('视频太短啦!不看不看~').description('过短提示'),
|
|
23
|
+
shortVideoUseImageParse: koishi_1.Schema.boolean().default(false).description('过短视频图文解析'),
|
|
24
|
+
maxVideoDuration: koishi_1.Schema.number().default(25).description('最大时长(分钟)'),
|
|
25
|
+
longVideoTip: koishi_1.Schema.string().default('视频太长啦!去B站看吧~').description('过长提示'),
|
|
26
|
+
longVideoUseImageParse: koishi_1.Schema.boolean().default(false).description('过长视频图文解析'),
|
|
27
|
+
maxFileSize: koishi_1.Schema.number().default(50).description('最大文件大小(MB)'),
|
|
28
|
+
imageParseFormat: koishi_1.Schema.string().default('${标题} ${tab} ${UP主}\n${简介}\n点赞:${点赞} ${tab} 投币:${投币}\n收藏:${收藏} ${tab} 转发:${转发}\n观看:${观看} ${tab} 弹幕:${弹幕}\n${~~~}\n${封面}').description('图文解析格式'),
|
|
29
|
+
showVideoLink: koishi_1.Schema.boolean().default(false).description('显示视频链接'),
|
|
30
|
+
maxDescLength: koishi_1.Schema.number().default(50).description('简介最大长度'),
|
|
31
|
+
enableMergeForward: koishi_1.Schema.boolean().default(false).description('开启合并转发(仅onebot)'),
|
|
32
|
+
downloadBeforeSend: koishi_1.Schema.boolean().default(false).description('下载后发送'),
|
|
33
|
+
messageBufferDelay: koishi_1.Schema.number().default(0).description('消息缓冲延迟(秒)'),
|
|
34
|
+
userAgent: koishi_1.Schema.string().default('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36').description('请求UA'),
|
|
35
|
+
publicApiKey: koishi_1.Schema.string().default('').description('公共解析API密钥'),
|
|
36
|
+
bilibili: koishi_1.Schema.object({
|
|
37
|
+
customApi: koishi_1.Schema.string().default('').description('B站自定义API地址'),
|
|
38
|
+
apiKey: koishi_1.Schema.string().default('').description('B站API密钥'),
|
|
39
|
+
fieldMap: koishi_1.Schema.object({
|
|
40
|
+
title: koishi_1.Schema.string().default('title'),
|
|
41
|
+
author: koishi_1.Schema.string().default('author'),
|
|
42
|
+
description: koishi_1.Schema.string().default('desc'),
|
|
43
|
+
like: koishi_1.Schema.string().default('likeCount'),
|
|
44
|
+
coin: koishi_1.Schema.string().default('coinCount'),
|
|
45
|
+
collect: koishi_1.Schema.string().default('collectCount'),
|
|
46
|
+
share: koishi_1.Schema.string().default('shareCount'),
|
|
47
|
+
view: koishi_1.Schema.string().default('viewCount'),
|
|
48
|
+
danmaku: koishi_1.Schema.string().default('danmakuCount'),
|
|
49
|
+
cover: koishi_1.Schema.string().default('cover'),
|
|
50
|
+
duration: koishi_1.Schema.string().default('duration'),
|
|
51
|
+
size: koishi_1.Schema.string().default('size'),
|
|
52
|
+
url: koishi_1.Schema.string().default('video_url')
|
|
53
|
+
}).description('B站字段映射')
|
|
54
|
+
}).description('B站配置'),
|
|
55
|
+
douyin: koishi_1.Schema.object({
|
|
56
|
+
customApi: koishi_1.Schema.string().default('').description('抖音自定义API地址'),
|
|
57
|
+
apiKey: koishi_1.Schema.string().default('').description('抖音API密钥'),
|
|
58
|
+
fieldMap: koishi_1.Schema.object({
|
|
59
|
+
title: koishi_1.Schema.string().default('title'),
|
|
60
|
+
author: koishi_1.Schema.string().default('author'),
|
|
61
|
+
description: koishi_1.Schema.string().default('desc'),
|
|
62
|
+
like: koishi_1.Schema.string().default('likeCount'),
|
|
63
|
+
coin: koishi_1.Schema.string().default('coinCount'),
|
|
64
|
+
collect: koishi_1.Schema.string().default('collectCount'),
|
|
65
|
+
share: koishi_1.Schema.string().default('shareCount'),
|
|
66
|
+
view: koishi_1.Schema.string().default('playCount'),
|
|
67
|
+
danmaku: koishi_1.Schema.string().default('commentCount'),
|
|
68
|
+
cover: koishi_1.Schema.string().default('cover'),
|
|
69
|
+
duration: koishi_1.Schema.string().default('duration'),
|
|
70
|
+
size: koishi_1.Schema.string().default('size'),
|
|
71
|
+
url: koishi_1.Schema.string().default('video_url')
|
|
72
|
+
}).description('抖音字段映射')
|
|
73
|
+
}).description('抖音配置'),
|
|
74
|
+
kuaishou: koishi_1.Schema.object({
|
|
75
|
+
customApi: koishi_1.Schema.string().default('').description('快手自定义API地址'),
|
|
76
|
+
apiKey: koishi_1.Schema.string().default('').description('快手API密钥'),
|
|
77
|
+
fieldMap: koishi_1.Schema.object({
|
|
78
|
+
title: koishi_1.Schema.string().default('title'),
|
|
79
|
+
author: koishi_1.Schema.string().default('author'),
|
|
80
|
+
description: koishi_1.Schema.string().default('desc'),
|
|
81
|
+
like: koishi_1.Schema.string().default('likeCount'),
|
|
82
|
+
coin: koishi_1.Schema.string().default('coinCount'),
|
|
83
|
+
collect: koishi_1.Schema.string().default('collectCount'),
|
|
84
|
+
share: koishi_1.Schema.string().default('shareCount'),
|
|
85
|
+
view: koishi_1.Schema.string().default('playCount'),
|
|
86
|
+
danmaku: koishi_1.Schema.string().default('commentCount'),
|
|
87
|
+
cover: koishi_1.Schema.string().default('cover'),
|
|
88
|
+
duration: koishi_1.Schema.string().default('duration'),
|
|
89
|
+
size: koishi_1.Schema.string().default('size'),
|
|
90
|
+
url: koishi_1.Schema.string().default('video_url')
|
|
91
|
+
}).description('快手字段映射')
|
|
92
|
+
}).description('快手配置')
|
|
93
|
+
});
|
|
94
|
+
const processedLinks = new Map();
|
|
95
|
+
const messageQueue = new Map();
|
|
96
|
+
function apply(ctx, config) {
|
|
97
|
+
const request = axios_1.default.create({
|
|
98
|
+
headers: { 'User-Agent': config.userAgent },
|
|
99
|
+
timeout: 30000
|
|
100
|
+
});
|
|
101
|
+
async function parseVideo(url, session) {
|
|
102
|
+
if (!config.enable)
|
|
103
|
+
return;
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
const linkHash = crypto_1.default.createHash('md5').update(url).digest('hex');
|
|
106
|
+
if (processedLinks.has(linkHash) && now - processedLinks.get(linkHash) < config.sameLinkInterval * 1000)
|
|
107
|
+
return;
|
|
108
|
+
processedLinks.set(linkHash, now);
|
|
109
|
+
if (config.showWaitingTip)
|
|
110
|
+
await session.send(config.waitingTipText);
|
|
111
|
+
let platform = '';
|
|
112
|
+
if (url.includes('bilibili') || /(BV|AV)\w+/.test(url))
|
|
113
|
+
platform = 'bilibili';
|
|
114
|
+
else if (url.includes('douyin') || url.includes('dy'))
|
|
115
|
+
platform = 'douyin';
|
|
116
|
+
else if (url.includes('kuaishou') || url.includes('ks'))
|
|
117
|
+
platform = 'kuaishou';
|
|
118
|
+
else
|
|
119
|
+
return await session.send('不支持的链接类型');
|
|
120
|
+
let videoInfo;
|
|
121
|
+
try {
|
|
122
|
+
if (config.parserSource === 'public') {
|
|
123
|
+
videoInfo = await parsePublicApi(url, platform);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
videoInfo = await parseCustomApi(url, platform);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
await session.send('解析失败,请稍后重试');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const duration = videoInfo.duration / 60;
|
|
134
|
+
if (duration < config.minVideoDuration) {
|
|
135
|
+
return config.shortVideoUseImageParse ? await generateImageParse(videoInfo, session) : await session.send(config.shortVideoTip);
|
|
136
|
+
}
|
|
137
|
+
if (duration > config.maxVideoDuration) {
|
|
138
|
+
return config.longVideoUseImageParse ? await generateImageParse(videoInfo, session) : await session.send(config.longVideoTip);
|
|
139
|
+
}
|
|
140
|
+
if (config.maxFileSize > 0 && videoInfo.size > config.maxFileSize * 1024 * 1024) {
|
|
141
|
+
return await session.send('视频文件过大,无法发送');
|
|
142
|
+
}
|
|
143
|
+
await generateReply(videoInfo, session);
|
|
144
|
+
}
|
|
145
|
+
async function parsePublicApi(url, platform) {
|
|
146
|
+
const res = await request.get('https://api.obtaindown.com/obApi/api/analysis', {
|
|
147
|
+
params: { url, key: config.publicApiKey }
|
|
148
|
+
});
|
|
149
|
+
const data = res.data.data || {};
|
|
150
|
+
return {
|
|
151
|
+
title: data.title || '',
|
|
152
|
+
author: data.author || data.userName || '',
|
|
153
|
+
description: data.desc || data.description || '',
|
|
154
|
+
like: data.likeCount || 0,
|
|
155
|
+
coin: data.coinCount || 0,
|
|
156
|
+
collect: data.collectCount || 0,
|
|
157
|
+
share: data.shareCount || 0,
|
|
158
|
+
view: data.viewCount || data.playCount || 0,
|
|
159
|
+
danmaku: data.danmakuCount || data.commentCount || 0,
|
|
160
|
+
cover: data.cover || data.thumbnail_url || '',
|
|
161
|
+
duration: data.duration || 0,
|
|
162
|
+
size: data.size || 0,
|
|
163
|
+
url: data.video_url || data.download_url || ''
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async function parseCustomApi(url, platform) {
|
|
167
|
+
const platformConfig = config[platform];
|
|
168
|
+
const res = await request.get(platformConfig.customApi, {
|
|
169
|
+
params: { url, key: platformConfig.apiKey }
|
|
170
|
+
});
|
|
171
|
+
const data = res.data.data || res.data;
|
|
172
|
+
const fieldMap = platformConfig.fieldMap;
|
|
173
|
+
// 简化嵌套字段取值逻辑
|
|
174
|
+
const getValue = (obj, path) => {
|
|
175
|
+
return path.split('.').reduce((o, k) => o?.[k], obj);
|
|
176
|
+
};
|
|
177
|
+
return {
|
|
178
|
+
title: getValue(data, fieldMap.title) || '',
|
|
179
|
+
author: getValue(data, fieldMap.author) || '',
|
|
180
|
+
description: getValue(data, fieldMap.description) || '',
|
|
181
|
+
like: getValue(data, fieldMap.like) || 0,
|
|
182
|
+
coin: getValue(data, fieldMap.coin) || 0,
|
|
183
|
+
collect: getValue(data, fieldMap.collect) || 0,
|
|
184
|
+
share: getValue(data, fieldMap.share) || 0,
|
|
185
|
+
view: getValue(data, fieldMap.view) || 0,
|
|
186
|
+
danmaku: getValue(data, fieldMap.danmaku) || 0,
|
|
187
|
+
cover: getValue(data, fieldMap.cover) || '',
|
|
188
|
+
duration: getValue(data, fieldMap.duration) || 0,
|
|
189
|
+
size: getValue(data, fieldMap.size) || 0,
|
|
190
|
+
url: getValue(data, fieldMap.url) || ''
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
async function generateImageParse(videoInfo, session) {
|
|
194
|
+
let content = config.imageParseFormat;
|
|
195
|
+
const desc = videoInfo.description.length > config.maxDescLength
|
|
196
|
+
? videoInfo.description.slice(0, config.maxDescLength) + '...'
|
|
197
|
+
: videoInfo.description;
|
|
198
|
+
content = content.replace(/\${标题}/g, videoInfo.title)
|
|
199
|
+
.replace(/\${UP主}/g, videoInfo.author)
|
|
200
|
+
.replace(/\${简介}/g, desc)
|
|
201
|
+
.replace(/\${点赞}/g, videoInfo.like)
|
|
202
|
+
.replace(/\${投币}/g, videoInfo.coin)
|
|
203
|
+
.replace(/\${收藏}/g, videoInfo.collect)
|
|
204
|
+
.replace(/\${转发}/g, videoInfo.share)
|
|
205
|
+
.replace(/\${观看}/g, videoInfo.view)
|
|
206
|
+
.replace(/\${弹幕}/g, videoInfo.danmaku)
|
|
207
|
+
.replace(/\${封面}/g, videoInfo.cover)
|
|
208
|
+
.replace(/\${tab}/g, '\t');
|
|
209
|
+
const parts = content.split(/\${~~~}/);
|
|
210
|
+
for (const p of parts) {
|
|
211
|
+
if (p.trim())
|
|
212
|
+
await session.send(p.trim());
|
|
213
|
+
}
|
|
214
|
+
if (config.showVideoLink)
|
|
215
|
+
await session.send(videoInfo.url);
|
|
216
|
+
}
|
|
217
|
+
async function generateReply(videoInfo, session) {
|
|
218
|
+
if (config.enableMergeForward) {
|
|
219
|
+
// 简化合并转发逻辑,直接发送消息数组
|
|
220
|
+
const msgs = [];
|
|
221
|
+
if (config.returnComponents.includes('title'))
|
|
222
|
+
msgs.push(koishi_1.h.text(videoInfo.title));
|
|
223
|
+
if (config.returnComponents.includes('author'))
|
|
224
|
+
msgs.push(koishi_1.h.text(videoInfo.author));
|
|
225
|
+
if (config.returnComponents.includes('cover'))
|
|
226
|
+
msgs.push(koishi_1.h.image(videoInfo.cover));
|
|
227
|
+
if (config.downloadBeforeSend) {
|
|
228
|
+
const stream = await request.get(videoInfo.url, { responseType: 'stream' });
|
|
229
|
+
msgs.push(koishi_1.h.video(stream.data));
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
msgs.push(koishi_1.h.video(videoInfo.url));
|
|
233
|
+
}
|
|
234
|
+
await session.send(msgs);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
await generateImageParse(videoInfo, session);
|
|
238
|
+
if (config.downloadBeforeSend) {
|
|
239
|
+
const stream = await request.get(videoInfo.url, { responseType: 'stream' });
|
|
240
|
+
await session.send(koishi_1.h.video(stream.data));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
await session.send(koishi_1.h.video(videoInfo.url));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
ctx.on('message', async (session) => {
|
|
248
|
+
if (!config.enable)
|
|
249
|
+
return;
|
|
250
|
+
const content = session.content.trim();
|
|
251
|
+
const reg = /(https?:\/\/\S+)|(BV\w+)|(AV\d+)/gi;
|
|
252
|
+
const matches = [...content.matchAll(reg)];
|
|
253
|
+
if (!matches.length)
|
|
254
|
+
return;
|
|
255
|
+
const uid = session.userId;
|
|
256
|
+
if (config.messageBufferDelay > 0) {
|
|
257
|
+
if (!messageQueue.has(uid)) {
|
|
258
|
+
messageQueue.set(uid, []);
|
|
259
|
+
setTimeout(async () => {
|
|
260
|
+
const links = [...new Set(messageQueue.get(uid))];
|
|
261
|
+
messageQueue.delete(uid);
|
|
262
|
+
for (const l of links)
|
|
263
|
+
await parseVideo(l, session);
|
|
264
|
+
}, config.messageBufferDelay * 1000);
|
|
265
|
+
}
|
|
266
|
+
matches.forEach(m => messageQueue.get(uid).push(m[0]));
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
for (const m of matches)
|
|
270
|
+
await parseVideo(m[0], session);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
// 清理过期链接记录
|
|
274
|
+
setInterval(() => {
|
|
275
|
+
const now = Date.now();
|
|
276
|
+
for (const [k, t] of processedLinks) {
|
|
277
|
+
if (now - t > 86400000)
|
|
278
|
+
processedLinks.delete(k);
|
|
279
|
+
}
|
|
280
|
+
}, 3600000);
|
|
281
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-video-parser-all",
|
|
3
|
+
"description": "Koishi 视频解析插件,支持抖音/快手/B站链接解析,可自定义API和解析规则",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"typings": "lib/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib"
|
|
9
|
+
],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc -w",
|
|
14
|
+
"clean": "rimraf lib"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"chatbot",
|
|
18
|
+
"koishi",
|
|
19
|
+
"plugin",
|
|
20
|
+
"video",
|
|
21
|
+
"parser",
|
|
22
|
+
"bilibili",
|
|
23
|
+
"douyin",
|
|
24
|
+
"kuaishou"
|
|
25
|
+
],
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@koishijs/client": "^5.30.4",
|
|
28
|
+
"@koishijs/scripts": "^4.6.2",
|
|
29
|
+
"rimraf": "^5.0.5",
|
|
30
|
+
"typescript": "^5.3.3"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"axios": "^1.6.8"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@koishijs/plugin-console": "^5.30.4",
|
|
37
|
+
"koishi": "^4.18.7"
|
|
38
|
+
}
|
|
39
|
+
}
|