koishi-plugin-custom-image 0.2.4 → 0.2.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/index.js +42 -180
- package/package.json +1 -1
- package/readme.md +83 -0
package/lib/index.js
CHANGED
|
@@ -33,60 +33,24 @@ const currentFilePath = worker_threads_1.isMainThread
|
|
|
33
33
|
: path_1.default.join(process.cwd(), worker_threads_1.isMainThread ? 'src/index.ts' : 'lib/index.js');
|
|
34
34
|
exports.name = 'custom-image';
|
|
35
35
|
exports.Config = koishi_1.Schema.object({
|
|
36
|
-
enable: koishi_1.Schema.boolean()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
.role('textarea')
|
|
49
|
-
.description('【基础设置】自定义图片API列表(每行一个地址)'),
|
|
50
|
-
customImageEnabled: koishi_1.Schema.boolean()
|
|
51
|
-
.default(true)
|
|
52
|
-
.description('【功能开关】启用自定义图片API功能'),
|
|
53
|
-
hsjpEnabled: koishi_1.Schema.boolean()
|
|
54
|
-
.default(true)
|
|
55
|
-
.description('【功能开关】启用黑丝举牌功能'),
|
|
56
|
-
dmjpEnabled: koishi_1.Schema.boolean()
|
|
57
|
-
.default(true)
|
|
58
|
-
.description('【功能开关】启用动漫举牌功能'),
|
|
59
|
-
imageSendTimeout: koishi_1.Schema.number()
|
|
60
|
-
.default(15000)
|
|
61
|
-
.min(0)
|
|
62
|
-
.description('【基础设置】图片发送超时(毫秒)'),
|
|
63
|
-
autoClearCacheInterval: koishi_1.Schema.number()
|
|
64
|
-
.default(60)
|
|
65
|
-
.min(0)
|
|
66
|
-
.description('【基础设置】自动清理缓存间隔(分钟)'),
|
|
67
|
-
tempDir: koishi_1.Schema.string()
|
|
68
|
-
.default(path_1.default.join(process.cwd(), 'temp_images'))
|
|
69
|
-
.description('【基础设置】临时图片保存目录'),
|
|
70
|
-
showSuccessTip: koishi_1.Schema.boolean()
|
|
71
|
-
.default(true)
|
|
72
|
-
.description('【提示设置】请求图片成功时显示提示'),
|
|
73
|
-
showTimeoutTip: koishi_1.Schema.boolean()
|
|
74
|
-
.default(true)
|
|
75
|
-
.description('【提示设置】API请求超时后给用户提示')
|
|
36
|
+
enable: koishi_1.Schema.boolean().default(true).description('启用插件'),
|
|
37
|
+
showWaitingTip: koishi_1.Schema.boolean().default(true).description('请求图片时显示等待提示'),
|
|
38
|
+
timeout: koishi_1.Schema.number().default(10000).min(0).description('API请求超时时间(毫秒)'),
|
|
39
|
+
customImageApis: koishi_1.Schema.array(koishi_1.Schema.string()).default([]).role('textarea').description('自定义图片API列表'),
|
|
40
|
+
customImageEnabled: koishi_1.Schema.boolean().default(true).description('启用自定义图片API功能'),
|
|
41
|
+
hsjpEnabled: koishi_1.Schema.boolean().default(true).description('启用黑丝举牌功能'),
|
|
42
|
+
dmjpEnabled: koishi_1.Schema.boolean().default(true).description('启用动漫举牌功能'),
|
|
43
|
+
imageSendTimeout: koishi_1.Schema.number().default(15000).min(0).description('图片发送超时(毫秒)'),
|
|
44
|
+
autoClearCacheInterval: koishi_1.Schema.number().default(60).min(0).description('自动清理缓存间隔(分钟)'),
|
|
45
|
+
tempDir: koishi_1.Schema.string().default(path_1.default.join(process.cwd(), 'temp_images')).description('临时图片保存目录'),
|
|
46
|
+
showSuccessTip: koishi_1.Schema.boolean().default(true).description('请求图片成功时显示提示'),
|
|
47
|
+
showTimeoutTip: koishi_1.Schema.boolean().default(true).description('API请求超时后给用户提示')
|
|
76
48
|
});
|
|
77
49
|
if (!worker_threads_1.isMainThread) {
|
|
78
50
|
const { url, filePath } = worker_threads_1.workerData;
|
|
79
51
|
(async () => {
|
|
80
52
|
try {
|
|
81
|
-
const response = await (0, axios_1.default)({
|
|
82
|
-
url,
|
|
83
|
-
method: 'GET',
|
|
84
|
-
responseType: 'stream',
|
|
85
|
-
timeout: 60000,
|
|
86
|
-
headers: {
|
|
87
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
88
|
-
}
|
|
89
|
-
});
|
|
53
|
+
const response = await (0, axios_1.default)({ url, method: 'GET', responseType: 'stream', timeout: 60000, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } });
|
|
90
54
|
await (0, promises_1.pipeline)(response.data, fs_1.default.createWriteStream(filePath));
|
|
91
55
|
worker_threads_1.parentPort?.postMessage({ success: true, filePath });
|
|
92
56
|
}
|
|
@@ -95,40 +59,27 @@ if (!worker_threads_1.isMainThread) {
|
|
|
95
59
|
}
|
|
96
60
|
})();
|
|
97
61
|
}
|
|
98
|
-
const processedApi = new Map();
|
|
99
|
-
const imageBuffer = new Map();
|
|
100
62
|
const delay = (ms) => new Promise(r => setTimeout(r, ms));
|
|
101
63
|
function getI18nText(session, key) {
|
|
102
|
-
if (session?.text)
|
|
64
|
+
if (session?.text)
|
|
103
65
|
return session.text(key);
|
|
104
|
-
}
|
|
105
66
|
const lang = 'zh-CN';
|
|
106
67
|
return locales[lang][key] || key;
|
|
107
68
|
}
|
|
108
69
|
async function sendTimeout(session, content, config) {
|
|
109
|
-
const text = typeof content === 'string'
|
|
110
|
-
|
|
111
|
-
: content;
|
|
112
|
-
if (config.imageSendTimeout <= 0) {
|
|
70
|
+
const text = typeof content === 'string' ? getI18nText(session, content) : content;
|
|
71
|
+
if (config.imageSendTimeout <= 0)
|
|
113
72
|
return session.send(text).catch(() => null);
|
|
114
|
-
|
|
115
|
-
return Promise.race([
|
|
116
|
-
session.send(text),
|
|
117
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), config.imageSendTimeout))
|
|
118
|
-
]).catch(() => null);
|
|
73
|
+
return Promise.race([session.send(text), new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), config.imageSendTimeout))]).catch(() => null);
|
|
119
74
|
}
|
|
120
75
|
function clearAllCache(config) {
|
|
121
|
-
processedApi.clear();
|
|
122
|
-
imageBuffer.forEach(buf => clearTimeout(buf.timer));
|
|
123
|
-
imageBuffer.clear();
|
|
124
76
|
if (fs_1.default.existsSync(config.tempDir)) {
|
|
125
77
|
fs_1.default.readdirSync(config.tempDir).forEach(file => {
|
|
126
78
|
try {
|
|
127
79
|
const filePath = path_1.default.join(config.tempDir, file);
|
|
128
80
|
const stat = fs_1.default.statSync(filePath);
|
|
129
|
-
if (Date.now() - stat.mtimeMs > 3600000)
|
|
81
|
+
if (Date.now() - stat.mtimeMs > 3600000)
|
|
130
82
|
fs_1.default.unlinkSync(filePath);
|
|
131
|
-
}
|
|
132
83
|
}
|
|
133
84
|
catch (error) { }
|
|
134
85
|
});
|
|
@@ -142,20 +93,13 @@ function randomSelectApi(customImageApis) {
|
|
|
142
93
|
return validApis[Math.floor(Math.random() * validApis.length)];
|
|
143
94
|
}
|
|
144
95
|
async function fetchImage(url, config) {
|
|
145
|
-
const http = axios_1.default.create({
|
|
146
|
-
timeout: config.timeout,
|
|
147
|
-
headers: {
|
|
148
|
-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
149
|
-
}
|
|
150
|
-
});
|
|
96
|
+
const http = axios_1.default.create({ timeout: config.timeout, headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' } });
|
|
151
97
|
try {
|
|
152
|
-
if (/^https?:\/\/.+\.(jpg|jpeg|png|gif|webp|bmp)/i.test(url))
|
|
98
|
+
if (/^https?:\/\/.+\.(jpg|jpeg|png|gif|webp|bmp)/i.test(url))
|
|
153
99
|
return { success: true, type: 'url', data: url, timeout: false };
|
|
154
|
-
}
|
|
155
100
|
const res = await http.get(url, { responseType: 'arraybuffer' });
|
|
156
|
-
if (res.status === 200 && res.data)
|
|
101
|
+
if (res.status === 200 && res.data)
|
|
157
102
|
return { success: true, type: 'buffer', data: res.data, timeout: false };
|
|
158
|
-
}
|
|
159
103
|
}
|
|
160
104
|
catch (error) {
|
|
161
105
|
const isTimeout = error.message.includes('timeout');
|
|
@@ -177,62 +121,18 @@ async function fetchDmjpImage(text, config) {
|
|
|
177
121
|
}
|
|
178
122
|
async function processCustomImage(session, apiUrl, config) {
|
|
179
123
|
const result = await fetchImage(apiUrl, config);
|
|
180
|
-
if (result.timeout && config.showTimeoutTip)
|
|
124
|
+
if (result.timeout && config.showTimeoutTip)
|
|
181
125
|
return { success: false, msg: '图片请求超时,请稍后再试' };
|
|
182
|
-
|
|
183
|
-
if (!result.success) {
|
|
126
|
+
if (!result.success)
|
|
184
127
|
return { success: false, msg: getI18nText(session, 'messages.fetchFailed') };
|
|
185
|
-
}
|
|
186
128
|
const imageElem = koishi_1.h.image(result.type === 'url' ? result.data : `data:image/jpeg;base64,${Buffer.from(result.data).toString('base64')}`);
|
|
187
129
|
const successText = config.showSuccessTip ? getI18nText(session, 'messages.fetchSuccess') : '';
|
|
188
130
|
return { success: true, msg: 'ok', data: { text: successText, image: imageElem } };
|
|
189
131
|
}
|
|
190
|
-
async function flush(session, config, manualApi) {
|
|
191
|
-
const key = `${session.platform}:${session.userId}:${session.channelId}`;
|
|
192
|
-
const buf = imageBuffer.get(key);
|
|
193
|
-
const apis = manualApi ? [manualApi] : buf?.apis || [];
|
|
194
|
-
if (buf) {
|
|
195
|
-
clearTimeout(buf.timer);
|
|
196
|
-
imageBuffer.delete(key);
|
|
197
|
-
}
|
|
198
|
-
if (!config.customImageEnabled || !apis.length)
|
|
199
|
-
return;
|
|
200
|
-
const items = [];
|
|
201
|
-
const errs = [];
|
|
202
|
-
for (const apiUrl of apis) {
|
|
203
|
-
const result = await processCustomImage(session, apiUrl, config);
|
|
204
|
-
if (result.success && result.data) {
|
|
205
|
-
items.push(result.data);
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
errs.push(`【${apiUrl.slice(0, 22)}...】:${result.msg}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (errs.length) {
|
|
212
|
-
const errorMsg = `${getI18nText(session, 'messages.partialFailed')}\n${errs.join('\n')}`;
|
|
213
|
-
await sendTimeout(session, errorMsg, config);
|
|
214
|
-
await delay(600);
|
|
215
|
-
}
|
|
216
|
-
if (items.length === 0) {
|
|
217
|
-
const failMsg = `${getI18nText(session, 'messages.allFailed')}\n${errs.join('\n')}`;
|
|
218
|
-
await sendTimeout(session, failMsg, config);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
for (const item of items) {
|
|
222
|
-
if (item.text) {
|
|
223
|
-
await sendTimeout(session, item.text, config);
|
|
224
|
-
await delay(300);
|
|
225
|
-
}
|
|
226
|
-
await sendTimeout(session, item.image, config);
|
|
227
|
-
await delay(1000);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
132
|
function apply(ctx, config) {
|
|
231
133
|
if (!worker_threads_1.isMainThread)
|
|
232
134
|
return;
|
|
233
|
-
Object.keys(locales).forEach(lang => {
|
|
234
|
-
ctx.i18n.define(lang, locales[lang]);
|
|
235
|
-
});
|
|
135
|
+
Object.keys(locales).forEach(lang => { ctx.i18n.define(lang, locales[lang]); });
|
|
236
136
|
clearAllCache(config);
|
|
237
137
|
ctx.logger.info('[custom-image] 插件已加载');
|
|
238
138
|
ctx.command('random-image [apis...]', locales['zh-CN']['commands.random-image'])
|
|
@@ -241,28 +141,21 @@ function apply(ctx, config) {
|
|
|
241
141
|
if (!config.enable || !config.customImageEnabled || !session)
|
|
242
142
|
return;
|
|
243
143
|
const targetApi = options.api || (apis.length ? apis.join(' ') : null);
|
|
244
|
-
if (
|
|
245
|
-
await
|
|
144
|
+
if (config.showWaitingTip)
|
|
145
|
+
await sendTimeout(session, 'messages.fetchWaiting', config);
|
|
146
|
+
const api = targetApi || randomSelectApi(config.customImageApis);
|
|
147
|
+
if (!api)
|
|
148
|
+
return;
|
|
149
|
+
const result = await processCustomImage(session, api, config);
|
|
150
|
+
if (result.success && result.data) {
|
|
151
|
+
if (result.data.text) {
|
|
152
|
+
await sendTimeout(session, result.data.text, config);
|
|
153
|
+
await delay(300);
|
|
154
|
+
}
|
|
155
|
+
await sendTimeout(session, result.data.image, config);
|
|
246
156
|
}
|
|
247
157
|
else {
|
|
248
|
-
|
|
249
|
-
let tipId;
|
|
250
|
-
if (config.showWaitingTip) {
|
|
251
|
-
const tip = await sendTimeout(session, 'messages.fetchWaiting', config);
|
|
252
|
-
tipId = tip?.messageId || tip?.id || tip;
|
|
253
|
-
}
|
|
254
|
-
if (imageBuffer.has(key)) {
|
|
255
|
-
const b = imageBuffer.get(key);
|
|
256
|
-
clearTimeout(b.timer);
|
|
257
|
-
b.timer = setTimeout(() => flush(session, config), 0);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
imageBuffer.set(key, {
|
|
261
|
-
apis: config.customImageApis,
|
|
262
|
-
timer: setTimeout(() => flush(session, config), 0),
|
|
263
|
-
tipMsgId: tipId
|
|
264
|
-
});
|
|
265
|
-
}
|
|
158
|
+
await sendTimeout(session, result.msg, config);
|
|
266
159
|
}
|
|
267
160
|
});
|
|
268
161
|
ctx.command('hsjp <msg> [msg1] [msg2]', locales['zh-CN']['commands.hsjp'])
|
|
@@ -273,9 +166,8 @@ function apply(ctx, config) {
|
|
|
273
166
|
await sendTimeout(session, 'messages.inputError', config);
|
|
274
167
|
return;
|
|
275
168
|
}
|
|
276
|
-
if (config.showWaitingTip)
|
|
169
|
+
if (config.showWaitingTip)
|
|
277
170
|
await sendTimeout(session, 'messages.fetchWaiting', config);
|
|
278
|
-
}
|
|
279
171
|
const result = await fetchHsjpImage(msg, msg1, msg2, config);
|
|
280
172
|
if (result.timeout && config.showTimeoutTip) {
|
|
281
173
|
await sendTimeout(session, '图片请求超时,请稍后再试', config);
|
|
@@ -301,9 +193,8 @@ function apply(ctx, config) {
|
|
|
301
193
|
await sendTimeout(session, 'messages.inputError', config);
|
|
302
194
|
return;
|
|
303
195
|
}
|
|
304
|
-
if (config.showWaitingTip)
|
|
196
|
+
if (config.showWaitingTip)
|
|
305
197
|
await sendTimeout(session, 'messages.fetchWaiting', config);
|
|
306
|
-
}
|
|
307
198
|
const result = await fetchDmjpImage(text, config);
|
|
308
199
|
if (result.timeout && config.showTimeoutTip) {
|
|
309
200
|
await sendTimeout(session, '图片请求超时,请稍后再试', config);
|
|
@@ -326,39 +217,10 @@ function apply(ctx, config) {
|
|
|
326
217
|
clearAllCache(config);
|
|
327
218
|
return session ? getI18nText(session, 'messages.cacheCleared') : '✅ 图片缓存已清空';
|
|
328
219
|
});
|
|
329
|
-
setInterval(() => {
|
|
330
|
-
const now = Date.now();
|
|
331
|
-
processedApi.forEach((timestamp, hash) => {
|
|
332
|
-
if (now - timestamp > 86400000)
|
|
333
|
-
processedApi.delete(hash);
|
|
334
|
-
});
|
|
335
|
-
}, 3600000);
|
|
336
|
-
setInterval(() => {
|
|
337
|
-
if (!fs_1.default.existsSync(config.tempDir))
|
|
338
|
-
return;
|
|
339
|
-
const now = Date.now();
|
|
340
|
-
fs_1.default.readdirSync(config.tempDir).forEach(file => {
|
|
341
|
-
try {
|
|
342
|
-
const stat = fs_1.default.statSync(path_1.default.join(config.tempDir, file));
|
|
343
|
-
if (now - stat.mtimeMs > 3600000) {
|
|
344
|
-
fs_1.default.unlinkSync(path_1.default.join(config.tempDir, file));
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
catch (error) { }
|
|
348
|
-
});
|
|
349
|
-
}, 1800000);
|
|
350
220
|
if (config.autoClearCacheInterval > 0) {
|
|
351
|
-
setInterval(() => {
|
|
352
|
-
clearAllCache(config);
|
|
353
|
-
ctx.logger.info('[custom-image] 缓存已自动清理');
|
|
354
|
-
}, config.autoClearCacheInterval * 60000);
|
|
221
|
+
setInterval(() => { clearAllCache(config); ctx.logger.info('[custom-image] 缓存已自动清理'); }, config.autoClearCacheInterval * 60000);
|
|
355
222
|
}
|
|
356
|
-
process.on('exit', () => {
|
|
357
|
-
clearAllCache(config);
|
|
358
|
-
ctx.logger.info('[custom-image] 插件缓存已清理');
|
|
359
|
-
});
|
|
223
|
+
process.on('exit', () => { clearAllCache(config); ctx.logger.info('[custom-image] 插件缓存已清理'); });
|
|
360
224
|
}
|
|
361
|
-
exports.inject = {
|
|
362
|
-
optional: ['i18n']
|
|
363
|
-
};
|
|
225
|
+
exports.inject = { optional: ['i18n'] };
|
|
364
226
|
exports.using = [];
|
package/package.json
CHANGED
package/readme.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# koishi-plugin-custom-image
|
|
2
|
+
|
|
3
|
+
## 项目介绍 (Project Introduction)
|
|
4
|
+
|
|
5
|
+
### 中文
|
|
6
|
+
这是一个为 Koishi 机器人框架开发的**随机图片获取插件**,支持从自定义 API 列表中随机选取接口获取图片,同时内置黑丝举牌、动漫举牌等趣味图片功能。核心特性:
|
|
7
|
+
- 🚀 从自定义 API 列表中**随机单张选取**,不批量、不轮询
|
|
8
|
+
- 🖼️ 强制使用图片 URL 直连发送,不下载本地文件
|
|
9
|
+
- 💡 可配置等待提示、成功提示、超时提示
|
|
10
|
+
- ⚙️ 简单易用的指令与配置项,开箱即用
|
|
11
|
+
- 🧹 支持自动清理缓存与手动清理指令
|
|
12
|
+
- 🎭 内置 `hsjp`、`dmjp` 等趣味图片接口
|
|
13
|
+
|
|
14
|
+
### English
|
|
15
|
+
A random image plugin for the Koishi bot framework. It randomly selects one API from your custom API list to fetch images, with built-in fun image APIs such as haisi and dongman. Core features:
|
|
16
|
+
- 🚀 Randomly select **one API** from the custom list, no batch / loop requests
|
|
17
|
+
- 🖼️ Force sending images via URL, no local file downloading
|
|
18
|
+
- 💡 Configurable waiting, success, and timeout tips
|
|
19
|
+
- ⚙️ Simple commands and configurations, ready to use
|
|
20
|
+
- 🧹 Auto cache cleanup & manual clear command
|
|
21
|
+
- 🎭 Built-in fun image APIs: `hsjp`, `dmjp`
|
|
22
|
+
|
|
23
|
+
## 项目仓库 (Repository)
|
|
24
|
+
- GitHub: https://github.com/yourname/koishi-plugin-custom-image
|
|
25
|
+
- Issues: https://github.com/yourname/koishi-plugin-custom-image/issues
|
|
26
|
+
|
|
27
|
+
## 核心指令 (Core Commands)
|
|
28
|
+
|
|
29
|
+
| 指令 (Command) | 说明 (Description) | 示例 (Example) |
|
|
30
|
+
|----------------|--------------------|----------------|
|
|
31
|
+
| `random-image` | 从自定义 API 列表随机获取一张图片 | `random-image` |
|
|
32
|
+
| `hsjp <msg> [msg1] [msg2]` | 生成黑丝举牌图片 | `hsjp 我喜欢你` |
|
|
33
|
+
| `dmjp <text>` | 生成动漫举牌图片 | `dmjp Koishi 真棒` |
|
|
34
|
+
| `clear-image-cache` | 清空图片缓存 | `clear-image-cache` |
|
|
35
|
+
|
|
36
|
+
## 配置项说明 (Configuration)
|
|
37
|
+
|
|
38
|
+
| 配置项 (Config Item) | 类型 (Type) | 默认值 (Default) | 说明 (Description) |
|
|
39
|
+
|----------------------|-------------|------------------|--------------------|
|
|
40
|
+
| `enable` | boolean | true | 是否启用插件 |
|
|
41
|
+
| `showWaitingTip` | boolean | true | 请求图片时是否显示等待提示 |
|
|
42
|
+
| `timeout` | number | 10000 | API 请求超时时间(毫秒) |
|
|
43
|
+
| `customImageApis` | string[] | [] | 自定义图片 API 列表 |
|
|
44
|
+
| `customImageEnabled` | boolean | true | 是否启用自定义图片功能 |
|
|
45
|
+
| `hsjpEnabled` | boolean | true | 是否启用黑丝举牌功能 |
|
|
46
|
+
| `dmjpEnabled` | boolean | true | 是否启用动漫举牌功能 |
|
|
47
|
+
| `imageSendTimeout` | number | 15000 | 图片发送超时(毫秒) |
|
|
48
|
+
| `autoClearCacheInterval` | number | 60 | 自动清理缓存间隔(分钟) |
|
|
49
|
+
| `tempDir` | string | ./temp_images | 临时图片保存目录 |
|
|
50
|
+
| `showSuccessTip` | boolean | true | 请求图片成功时是否显示提示 |
|
|
51
|
+
| `showTimeoutTip` | boolean | true | API 请求超时后是否给用户提示 |
|
|
52
|
+
|
|
53
|
+
## 支持功能 (Supported Features)
|
|
54
|
+
|
|
55
|
+
| 功能 (Feature) | 状态 (Status) |
|
|
56
|
+
|----------------|---------------|
|
|
57
|
+
| 自定义 API 随机图片 | ✅ 稳定 |
|
|
58
|
+
| 黑丝举牌图片 | ✅ 稳定 |
|
|
59
|
+
| 动漫举牌图片 | ✅ 稳定 |
|
|
60
|
+
| 手动清理缓存 | ✅ 稳定 |
|
|
61
|
+
| 自动清理缓存 | ✅ 稳定 |
|
|
62
|
+
| 超时提示开关 | ✅ 稳定 |
|
|
63
|
+
| 成功提示开关 | ✅ 稳定 |
|
|
64
|
+
|
|
65
|
+
## 项目贡献者 (Contributors)
|
|
66
|
+
|
|
67
|
+
| 贡献者 (Contributor) | 贡献内容 (Contribution) |
|
|
68
|
+
|----------------------|-------------------------|
|
|
69
|
+
| Minecraft-1314 | 插件完整开发 (Complete plugin development) |
|
|
70
|
+
| 素颜API | 提供 API 接口支持 |
|
|
71
|
+
| (欢迎提交 PR 加入贡献者列表) | (Welcome to submit PR to join the contributor list) |
|
|
72
|
+
|
|
73
|
+
## 许可协议 (License)
|
|
74
|
+
|
|
75
|
+
本项目采用 MIT 许可证,详情参见 [LICENSE](LICENSE) 文件。
|
|
76
|
+
|
|
77
|
+
This project is licensed under the MIT License, see the [LICENSE](LICENSE) file for details.
|
|
78
|
+
|
|
79
|
+
## 支持我们 (Support Us)
|
|
80
|
+
|
|
81
|
+
如果这个项目对您有帮助,欢迎点亮右上角的 Star ⭐ 支持我们,这将是对所有贡献者最大的鼓励!
|
|
82
|
+
|
|
83
|
+
If this project is helpful to you, please feel free to star it in the upper right corner ⭐ to support us, which will be the greatest encouragement to all contributors!
|