koishi-plugin-custom-image-api 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 ADDED
@@ -0,0 +1,44 @@
1
+ import { Context, Schema } from 'koishi';
2
+ export declare const name = "koishi-plugin-custom-image-api";
3
+ export declare const inject: string[];
4
+ export interface CustomImageApiItem {
5
+ name: string;
6
+ url: string;
7
+ enabled: boolean;
8
+ }
9
+ export interface CustomSignApiItem {
10
+ name: string;
11
+ url: string;
12
+ paramName: string;
13
+ enabled: boolean;
14
+ }
15
+ export interface PluginConfig {
16
+ enableTextReply: boolean;
17
+ hsjpEnabled: boolean;
18
+ dmjpEnabled: boolean;
19
+ customImageApis: CustomImageApiItem[];
20
+ customSignApis: CustomSignApiItem[];
21
+ timeout: number;
22
+ successMessages: {
23
+ imageSuccess: string;
24
+ hsjpSuccess: string;
25
+ dmjpSuccess: string;
26
+ customSignSuccess: string;
27
+ };
28
+ tipMessages: {
29
+ noEnabledImageApi: string;
30
+ hsjpMissingMsg: string;
31
+ dmjpMissingText: string;
32
+ customSignMissingParam: string;
33
+ customSignNotFound: string;
34
+ apiListTitle: string;
35
+ imageApiSubtitle: string;
36
+ signApiSubtitle: string;
37
+ noImageApiConfigured: string;
38
+ noSignApiConfigured: string;
39
+ enabled: string;
40
+ disabled: string;
41
+ };
42
+ }
43
+ export declare const Config: Schema<PluginConfig>;
44
+ export declare function apply(ctx: Context, config: PluginConfig): void;
package/lib/index.js ADDED
@@ -0,0 +1,206 @@
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.inject = exports.name = void 0;
7
+ exports.apply = apply;
8
+ const koishi_1 = require("koishi");
9
+ const axios_1 = __importDefault(require("axios"));
10
+ exports.name = 'koishi-plugin-custom-image-api';
11
+ exports.inject = ['axios'];
12
+ exports.Config = koishi_1.Schema.object({
13
+ enableTextReply: koishi_1.Schema.boolean().default(true),
14
+ hsjpEnabled: koishi_1.Schema.boolean().default(true),
15
+ dmjpEnabled: koishi_1.Schema.boolean().default(true),
16
+ customImageApis: koishi_1.Schema.array(koishi_1.Schema.object({
17
+ name: koishi_1.Schema.string(),
18
+ url: koishi_1.Schema.string(),
19
+ enabled: koishi_1.Schema.boolean().default(true)
20
+ })).default([]),
21
+ customSignApis: koishi_1.Schema.array(koishi_1.Schema.object({
22
+ name: koishi_1.Schema.string(),
23
+ url: koishi_1.Schema.string(),
24
+ paramName: koishi_1.Schema.string(),
25
+ enabled: koishi_1.Schema.boolean().default(true)
26
+ })).default([]),
27
+ timeout: koishi_1.Schema.number().default(10000),
28
+ successMessages: koishi_1.Schema.object({
29
+ imageSuccess: koishi_1.Schema.string().default('成功从「{{apiName}}」获取图片 ✨'),
30
+ hsjpSuccess: koishi_1.Schema.string().default('黑丝举牌图片生成成功 ✨'),
31
+ dmjpSuccess: koishi_1.Schema.string().default('动漫举牌图片生成成功 ✨'),
32
+ customSignSuccess: koishi_1.Schema.string().default('成功调用「{{name}}」举牌API生成图片 ✨')
33
+ }).default({
34
+ imageSuccess: '成功从「{{apiName}}」获取图片 ✨',
35
+ hsjpSuccess: '黑丝举牌图片生成成功 ✨',
36
+ dmjpSuccess: '动漫举牌图片生成成功 ✨',
37
+ customSignSuccess: '成功调用「{{name}}」举牌API生成图片 ✨'
38
+ }),
39
+ tipMessages: koishi_1.Schema.object({
40
+ noEnabledImageApi: koishi_1.Schema.string().default('暂无启用的自定义图片API,请先在配置页面添加并启用!'),
41
+ hsjpMissingMsg: koishi_1.Schema.string().default('缺少必填参数!用法:hsjp <第一行文字> [第二行文字] [第三行文字]'),
42
+ dmjpMissingText: koishi_1.Schema.string().default('缺少必填参数!用法:dmjp <文本内容>'),
43
+ customSignMissingParam: koishi_1.Schema.string().default('缺少必填参数!用法:custom-sign <举牌API名称> <文本内容>'),
44
+ customSignNotFound: koishi_1.Schema.string().default('未找到启用的自定义举牌API「{{name}}」!'),
45
+ apiListTitle: koishi_1.Schema.string().default('已配置的自定义API列表:'),
46
+ imageApiSubtitle: koishi_1.Schema.string().default('--- 自定义图片API ---'),
47
+ signApiSubtitle: koishi_1.Schema.string().default('--- 自定义举牌API ---'),
48
+ noImageApiConfigured: koishi_1.Schema.string().default('暂无配置任何自定义图片API!'),
49
+ noSignApiConfigured: koishi_1.Schema.string().default('暂无配置任何自定义举牌API!'),
50
+ enabled: koishi_1.Schema.string().default('已启用'),
51
+ disabled: koishi_1.Schema.string().default('已禁用')
52
+ }).default({
53
+ noEnabledImageApi: '暂无启用的自定义图片API,请先在配置页面添加并启用!',
54
+ hsjpMissingMsg: '缺少必填参数!用法:hsjp <第一行文字> [第二行文字] [第三行文字]',
55
+ dmjpMissingText: '缺少必填参数!用法:dmjp <文本内容>',
56
+ customSignMissingParam: '缺少必填参数!用法:custom-sign <举牌API名称> <文本内容>',
57
+ customSignNotFound: '未找到启用的自定义举牌API「{{name}}」!',
58
+ apiListTitle: '已配置的自定义API列表:',
59
+ imageApiSubtitle: '--- 自定义图片API ---',
60
+ signApiSubtitle: '--- 自定义举牌API ---',
61
+ noImageApiConfigured: '暂无配置任何自定义图片API!',
62
+ noSignApiConfigured: '暂无配置任何自定义举牌API!',
63
+ enabled: '已启用',
64
+ disabled: '已禁用'
65
+ })
66
+ });
67
+ function apply(ctx, config) {
68
+ const logger = new koishi_1.Logger('koishi-plugin-custom-image-api');
69
+ ctx.command('random-image')
70
+ .action(async ({ session }) => {
71
+ try {
72
+ const enabledApis = config.customImageApis.filter(api => api.enabled);
73
+ if (enabledApis.length === 0) {
74
+ return config.enableTextReply ? config.tipMessages.noEnabledImageApi : '';
75
+ }
76
+ const randomApi = enabledApis[Math.floor(Math.random() * enabledApis.length)];
77
+ logger.info(`随机选择图片API: ${randomApi.name}, URL: ${randomApi.url}`);
78
+ const response = await (0, axios_1.default)({
79
+ url: randomApi.url,
80
+ method: 'GET',
81
+ timeout: config.timeout,
82
+ responseType: 'arraybuffer'
83
+ });
84
+ const imageBuffer = Buffer.from(response.data);
85
+ const imageElement = koishi_1.segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`);
86
+ if (session)
87
+ await session.send(imageElement);
88
+ const successMsg = config.successMessages.imageSuccess.replace('{{apiName}}', randomApi.name);
89
+ return config.enableTextReply ? successMsg : '';
90
+ }
91
+ catch (error) {
92
+ logger.error(`获取图片失败: ${error.message}`);
93
+ return '';
94
+ }
95
+ });
96
+ ctx.command('hsjp <msg> [msg1] [msg2]')
97
+ .action(async ({ session }, msg, msg1 = '', msg2 = '') => {
98
+ if (!config.hsjpEnabled)
99
+ return '';
100
+ if (!msg) {
101
+ return config.enableTextReply ? config.tipMessages.hsjpMissingMsg : '';
102
+ }
103
+ try {
104
+ const apiUrl = `https://api.suyanw.cn/api/hsjp/?rgb1=0&rgb2=0&rgb3=0&msg=${encodeURIComponent(msg)}&msg1=${encodeURIComponent(msg1)}&msg2=${encodeURIComponent(msg2)}`;
105
+ logger.info(`调用黑丝举牌API: ${apiUrl}`);
106
+ const response = await (0, axios_1.default)({
107
+ url: apiUrl,
108
+ method: 'GET',
109
+ timeout: config.timeout,
110
+ responseType: 'arraybuffer'
111
+ });
112
+ const imageBuffer = Buffer.from(response.data);
113
+ const imageElement = koishi_1.segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`);
114
+ if (session)
115
+ await session.send(imageElement);
116
+ return config.enableTextReply ? config.successMessages.hsjpSuccess : '';
117
+ }
118
+ catch (error) {
119
+ logger.error(`黑丝举牌API调用失败: ${error.message}`);
120
+ return '';
121
+ }
122
+ });
123
+ ctx.command('dmjp <text>')
124
+ .action(async ({ session }, text) => {
125
+ if (!config.dmjpEnabled)
126
+ return '';
127
+ if (!text) {
128
+ return config.enableTextReply ? config.tipMessages.dmjpMissingText : '';
129
+ }
130
+ try {
131
+ const apiUrl = `https://api.suyanw.cn/api/dmjp.php?text=${encodeURIComponent(text)}`;
132
+ logger.info(`调用动漫举牌API: ${apiUrl}`);
133
+ const response = await (0, axios_1.default)({
134
+ url: apiUrl,
135
+ method: 'GET',
136
+ timeout: config.timeout,
137
+ responseType: 'arraybuffer'
138
+ });
139
+ const imageBuffer = Buffer.from(response.data);
140
+ const imageElement = koishi_1.segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`);
141
+ if (session)
142
+ await session.send(imageElement);
143
+ return config.enableTextReply ? config.successMessages.dmjpSuccess : '';
144
+ }
145
+ catch (error) {
146
+ logger.error(`动漫举牌API调用失败: ${error.message}`);
147
+ return '';
148
+ }
149
+ });
150
+ ctx.command('custom-sign <name> <text>')
151
+ .action(async ({ session }, name, text) => {
152
+ if (!name || !text) {
153
+ return config.enableTextReply ? config.tipMessages.customSignMissingParam : '';
154
+ }
155
+ const targetApi = config.customSignApis.find(api => api.name === name && api.enabled);
156
+ if (!targetApi) {
157
+ const notFoundMsg = config.tipMessages.customSignNotFound.replace('{{name}}', name);
158
+ return config.enableTextReply ? notFoundMsg : '';
159
+ }
160
+ try {
161
+ const apiUrl = `${targetApi.url}?${targetApi.paramName}=${encodeURIComponent(text)}`;
162
+ logger.info(`调用自定义举牌API: ${targetApi.name}, URL: ${apiUrl}`);
163
+ const response = await (0, axios_1.default)({
164
+ url: apiUrl,
165
+ method: 'GET',
166
+ timeout: config.timeout,
167
+ responseType: 'arraybuffer'
168
+ });
169
+ const imageBuffer = Buffer.from(response.data);
170
+ const imageElement = koishi_1.segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`);
171
+ if (session)
172
+ await session.send(imageElement);
173
+ const successMsg = config.successMessages.customSignSuccess.replace('{{name}}', targetApi.name);
174
+ return config.enableTextReply ? successMsg : '';
175
+ }
176
+ catch (error) {
177
+ logger.error(`自定义举牌API调用失败: ${error.message}`);
178
+ return '';
179
+ }
180
+ });
181
+ ctx.command('image-api list', '列出所有已配置的自定义API')
182
+ .action(({ session }) => {
183
+ if (!config.enableTextReply)
184
+ return '';
185
+ let list = config.tipMessages.apiListTitle + '\n';
186
+ list += config.tipMessages.imageApiSubtitle + '\n';
187
+ if (config.customImageApis.length === 0) {
188
+ list += config.tipMessages.noImageApiConfigured + '\n';
189
+ }
190
+ else {
191
+ config.customImageApis.forEach((api, index) => {
192
+ list += `${index + 1}. ${api.name} - ${api.enabled ? config.tipMessages.enabled : config.tipMessages.disabled} - ${api.url}\n`;
193
+ });
194
+ }
195
+ list += '\n' + config.tipMessages.signApiSubtitle + '\n';
196
+ if (config.customSignApis.length === 0) {
197
+ list += config.tipMessages.noSignApiConfigured + '\n';
198
+ }
199
+ else {
200
+ config.customSignApis.forEach((api, index) => {
201
+ list += `${index + 1}. ${api.name} - ${api.enabled ? config.tipMessages.enabled : config.tipMessages.disabled} - ${api.url} (参数: ${api.paramName})\n`;
202
+ });
203
+ }
204
+ return list;
205
+ });
206
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "koishi-plugin-custom-image-api",
3
+ "version": "0.0.1",
4
+ "description": "Koishi插件:自定义图片API随机调用 + 内置黑丝/动漫举牌 + 自定义举牌功能",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "src"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsc -w"
14
+ },
15
+ "keywords": [
16
+ "koishi",
17
+ "plugin",
18
+ "image",
19
+ "api",
20
+ "sign",
21
+ "举牌"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/Minecraft-1314/koishi-plugin-custom-image-api.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/Minecraft-1314/koishi-plugin-custom-image-api/issues"
29
+ },
30
+ "homepage": "https://github.com/Minecraft-1314/koishi-plugin-custom-image-api#readme",
31
+ "author": "",
32
+ "license": "MIT",
33
+ "peerDependencies": {
34
+ "koishi": "^4.0.0",
35
+ "axios": "^1.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "typescript": "^5.3.3",
39
+ "@types/node": "^20.11.17",
40
+ "@koishijs/typings": "^4.0.0"
41
+ }
42
+ }
package/readme.md ADDED
@@ -0,0 +1,5 @@
1
+ # koishi-plugin-custom-image-api
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-custom-image-api?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-custom-image-api)
4
+
5
+
package/src/index.ts ADDED
@@ -0,0 +1,255 @@
1
+ import { Context, Schema, segment, Logger, Session } from 'koishi'
2
+ import axios from 'axios'
3
+
4
+ export const name = 'koishi-plugin-custom-image-api'
5
+ export const inject = ['axios']
6
+
7
+ export interface CustomImageApiItem {
8
+ name: string
9
+ url: string
10
+ enabled: boolean
11
+ }
12
+
13
+ export interface CustomSignApiItem {
14
+ name: string
15
+ url: string
16
+ paramName: string
17
+ enabled: boolean
18
+ }
19
+
20
+ export interface PluginConfig {
21
+ enableTextReply: boolean
22
+ hsjpEnabled: boolean
23
+ dmjpEnabled: boolean
24
+ customImageApis: CustomImageApiItem[]
25
+ customSignApis: CustomSignApiItem[]
26
+ timeout: number
27
+ successMessages: {
28
+ imageSuccess: string
29
+ hsjpSuccess: string
30
+ dmjpSuccess: string
31
+ customSignSuccess: string
32
+ }
33
+ tipMessages: {
34
+ noEnabledImageApi: string
35
+ hsjpMissingMsg: string
36
+ dmjpMissingText: string
37
+ customSignMissingParam: string
38
+ customSignNotFound: string
39
+ apiListTitle: string
40
+ imageApiSubtitle: string
41
+ signApiSubtitle: string
42
+ noImageApiConfigured: string
43
+ noSignApiConfigured: string
44
+ enabled: string
45
+ disabled: string
46
+ }
47
+ }
48
+
49
+ export const Config: Schema<PluginConfig> = Schema.object({
50
+ enableTextReply: Schema.boolean().default(true),
51
+ hsjpEnabled: Schema.boolean().default(true),
52
+ dmjpEnabled: Schema.boolean().default(true),
53
+ customImageApis: Schema.array(Schema.object({
54
+ name: Schema.string(),
55
+ url: Schema.string(),
56
+ enabled: Schema.boolean().default(true)
57
+ })).default([]),
58
+ customSignApis: Schema.array(Schema.object({
59
+ name: Schema.string(),
60
+ url: Schema.string(),
61
+ paramName: Schema.string(),
62
+ enabled: Schema.boolean().default(true)
63
+ })).default([]),
64
+ timeout: Schema.number().default(10000),
65
+ successMessages: Schema.object({
66
+ imageSuccess: Schema.string().default('成功从「{{apiName}}」获取图片 ✨'),
67
+ hsjpSuccess: Schema.string().default('黑丝举牌图片生成成功 ✨'),
68
+ dmjpSuccess: Schema.string().default('动漫举牌图片生成成功 ✨'),
69
+ customSignSuccess: Schema.string().default('成功调用「{{name}}」举牌API生成图片 ✨')
70
+ }).default({
71
+ imageSuccess: '成功从「{{apiName}}」获取图片 ✨',
72
+ hsjpSuccess: '黑丝举牌图片生成成功 ✨',
73
+ dmjpSuccess: '动漫举牌图片生成成功 ✨',
74
+ customSignSuccess: '成功调用「{{name}}」举牌API生成图片 ✨'
75
+ }),
76
+ tipMessages: Schema.object({
77
+ noEnabledImageApi: Schema.string().default('暂无启用的自定义图片API,请先在配置页面添加并启用!'),
78
+ hsjpMissingMsg: Schema.string().default('缺少必填参数!用法:hsjp <第一行文字> [第二行文字] [第三行文字]'),
79
+ dmjpMissingText: Schema.string().default('缺少必填参数!用法:dmjp <文本内容>'),
80
+ customSignMissingParam: Schema.string().default('缺少必填参数!用法:custom-sign <举牌API名称> <文本内容>'),
81
+ customSignNotFound: Schema.string().default('未找到启用的自定义举牌API「{{name}}」!'),
82
+ apiListTitle: Schema.string().default('已配置的自定义API列表:'),
83
+ imageApiSubtitle: Schema.string().default('--- 自定义图片API ---'),
84
+ signApiSubtitle: Schema.string().default('--- 自定义举牌API ---'),
85
+ noImageApiConfigured: Schema.string().default('暂无配置任何自定义图片API!'),
86
+ noSignApiConfigured: Schema.string().default('暂无配置任何自定义举牌API!'),
87
+ enabled: Schema.string().default('已启用'),
88
+ disabled: Schema.string().default('已禁用')
89
+ }).default({
90
+ noEnabledImageApi: '暂无启用的自定义图片API,请先在配置页面添加并启用!',
91
+ hsjpMissingMsg: '缺少必填参数!用法:hsjp <第一行文字> [第二行文字] [第三行文字]',
92
+ dmjpMissingText: '缺少必填参数!用法:dmjp <文本内容>',
93
+ customSignMissingParam: '缺少必填参数!用法:custom-sign <举牌API名称> <文本内容>',
94
+ customSignNotFound: '未找到启用的自定义举牌API「{{name}}」!',
95
+ apiListTitle: '已配置的自定义API列表:',
96
+ imageApiSubtitle: '--- 自定义图片API ---',
97
+ signApiSubtitle: '--- 自定义举牌API ---',
98
+ noImageApiConfigured: '暂无配置任何自定义图片API!',
99
+ noSignApiConfigured: '暂无配置任何自定义举牌API!',
100
+ enabled: '已启用',
101
+ disabled: '已禁用'
102
+ })
103
+ })
104
+
105
+ export function apply(ctx: Context, config: PluginConfig) {
106
+ const logger = new Logger('koishi-plugin-custom-image-api')
107
+
108
+ ctx.command('random-image')
109
+ .action(async ({ session }: { session?: Session }) => {
110
+ try {
111
+ const enabledApis = config.customImageApis.filter(api => api.enabled)
112
+ if (enabledApis.length === 0) {
113
+ return config.enableTextReply ? config.tipMessages.noEnabledImageApi : ''
114
+ }
115
+
116
+ const randomApi = enabledApis[Math.floor(Math.random() * enabledApis.length)]
117
+ logger.info(`随机选择图片API: ${randomApi.name}, URL: ${randomApi.url}`)
118
+
119
+ const response = await axios({
120
+ url: randomApi.url,
121
+ method: 'GET',
122
+ timeout: config.timeout,
123
+ responseType: 'arraybuffer'
124
+ })
125
+
126
+ const imageBuffer = Buffer.from(response.data)
127
+ const imageElement = segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`)
128
+ if (session) await session.send(imageElement)
129
+
130
+ const successMsg = config.successMessages.imageSuccess.replace('{{apiName}}', randomApi.name)
131
+ return config.enableTextReply ? successMsg : ''
132
+ } catch (error) {
133
+ logger.error(`获取图片失败: ${(error as Error).message}`)
134
+ return ''
135
+ }
136
+ })
137
+
138
+ ctx.command('hsjp <msg> [msg1] [msg2]')
139
+ .action(async ({ session }: { session?: Session }, msg: string, msg1: string = '', msg2: string = '') => {
140
+ if (!config.hsjpEnabled) return ''
141
+ if (!msg) {
142
+ return config.enableTextReply ? config.tipMessages.hsjpMissingMsg : ''
143
+ }
144
+
145
+ try {
146
+ const apiUrl = `https://api.suyanw.cn/api/hsjp/?rgb1=0&rgb2=0&rgb3=0&msg=${encodeURIComponent(msg)}&msg1=${encodeURIComponent(msg1)}&msg2=${encodeURIComponent(msg2)}`
147
+ logger.info(`调用黑丝举牌API: ${apiUrl}`)
148
+
149
+ const response = await axios({
150
+ url: apiUrl,
151
+ method: 'GET',
152
+ timeout: config.timeout,
153
+ responseType: 'arraybuffer'
154
+ })
155
+
156
+ const imageBuffer = Buffer.from(response.data)
157
+ const imageElement = segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`)
158
+ if (session) await session.send(imageElement)
159
+ return config.enableTextReply ? config.successMessages.hsjpSuccess : ''
160
+ } catch (error) {
161
+ logger.error(`黑丝举牌API调用失败: ${(error as Error).message}`)
162
+ return ''
163
+ }
164
+ })
165
+
166
+ ctx.command('dmjp <text>')
167
+ .action(async ({ session }: { session?: Session }, text: string) => {
168
+ if (!config.dmjpEnabled) return ''
169
+ if (!text) {
170
+ return config.enableTextReply ? config.tipMessages.dmjpMissingText : ''
171
+ }
172
+
173
+ try {
174
+ const apiUrl = `https://api.suyanw.cn/api/dmjp.php?text=${encodeURIComponent(text)}`
175
+ logger.info(`调用动漫举牌API: ${apiUrl}`)
176
+
177
+ const response = await axios({
178
+ url: apiUrl,
179
+ method: 'GET',
180
+ timeout: config.timeout,
181
+ responseType: 'arraybuffer'
182
+ })
183
+
184
+ const imageBuffer = Buffer.from(response.data)
185
+ const imageElement = segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`)
186
+ if (session) await session.send(imageElement)
187
+ return config.enableTextReply ? config.successMessages.dmjpSuccess : ''
188
+ } catch (error) {
189
+ logger.error(`动漫举牌API调用失败: ${(error as Error).message}`)
190
+ return ''
191
+ }
192
+ })
193
+
194
+ ctx.command('custom-sign <name> <text>')
195
+ .action(async ({ session }: { session?: Session }, name: string, text: string) => {
196
+ if (!name || !text) {
197
+ return config.enableTextReply ? config.tipMessages.customSignMissingParam : ''
198
+ }
199
+
200
+ const targetApi = config.customSignApis.find(api => api.name === name && api.enabled)
201
+ if (!targetApi) {
202
+ const notFoundMsg = config.tipMessages.customSignNotFound.replace('{{name}}', name)
203
+ return config.enableTextReply ? notFoundMsg : ''
204
+ }
205
+
206
+ try {
207
+ const apiUrl = `${targetApi.url}?${targetApi.paramName}=${encodeURIComponent(text)}`
208
+ logger.info(`调用自定义举牌API: ${targetApi.name}, URL: ${apiUrl}`)
209
+
210
+ const response = await axios({
211
+ url: apiUrl,
212
+ method: 'GET',
213
+ timeout: config.timeout,
214
+ responseType: 'arraybuffer'
215
+ })
216
+
217
+ const imageBuffer = Buffer.from(response.data)
218
+ const imageElement = segment.image(`data:image/jpeg;base64,${imageBuffer.toString('base64')}`)
219
+ if (session) await session.send(imageElement)
220
+
221
+ const successMsg = config.successMessages.customSignSuccess.replace('{{name}}', targetApi.name)
222
+ return config.enableTextReply ? successMsg : ''
223
+ } catch (error) {
224
+ logger.error(`自定义举牌API调用失败: ${(error as Error).message}`)
225
+ return ''
226
+ }
227
+ })
228
+
229
+ ctx.command('image-api list', '列出所有已配置的自定义API')
230
+ .action(({ session }: { session?: Session }) => {
231
+ if (!config.enableTextReply) return ''
232
+
233
+ let list = config.tipMessages.apiListTitle + '\n'
234
+
235
+ list += config.tipMessages.imageApiSubtitle + '\n'
236
+ if (config.customImageApis.length === 0) {
237
+ list += config.tipMessages.noImageApiConfigured + '\n'
238
+ } else {
239
+ config.customImageApis.forEach((api, index) => {
240
+ list += `${index + 1}. ${api.name} - ${api.enabled ? config.tipMessages.enabled : config.tipMessages.disabled} - ${api.url}\n`
241
+ })
242
+ }
243
+
244
+ list += '\n' + config.tipMessages.signApiSubtitle + '\n'
245
+ if (config.customSignApis.length === 0) {
246
+ list += config.tipMessages.noSignApiConfigured + '\n'
247
+ } else {
248
+ config.customSignApis.forEach((api, index) => {
249
+ list += `${index + 1}. ${api.name} - ${api.enabled ? config.tipMessages.enabled : config.tipMessages.disabled} - ${api.url} (参数: ${api.paramName})\n`
250
+ })
251
+ }
252
+
253
+ return list
254
+ })
255
+ }