@nenekusanagi/koishi-plugin-setu 1.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019-present Shigma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+ <div align="center">
2
+ <img src="https://raw.githubusercontent.com/chitsanfei/koishi-plugin-setu/master/assets/koimu.png" height="200" alt="koishi-plugin-setu">
3
+ <h1>koishi-plugin-setu</h1>
4
+ <b>一个支持多 API 提供商的色图插件,基于 Koishi 框架开发</b>
5
+ </div>
6
+
7
+ ---
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@nenekusanagi/koishi-plugin-setu.svg)](https://www.npmjs.com/package/@nenekusanagi/koishi-plugin-setu)
10
+ [![GitHub stars](https://img.shields.io/github/stars/chitsanfei/koishi-plugin-setu)](https://github.com/chitsanfei/koishi-plugin-setu/stargazers)
11
+ [![GitHub issues](https://img.shields.io/github/issues/chitsanfei/koishi-plugin-setu)](https://github.com/chitsanfei/koishi-plugin-setu/issues)
12
+ [![GitHub forks](https://img.shields.io/github/forks/chitsanfei/koishi-plugin-setu)](https://github.com/chitsanfei/koishi-plugin-setu/network)
13
+ [![GitHub license](https://img.shields.io/github/license/chitsanfei/koishi-plugin-setu)](https://github.com/chitsanfei/koishi-plugin-setu/blob/master/LICENSE)
14
+
15
+ ---
16
+
17
+ ## ✨ 功能特性
18
+
19
+ - 🎯 支持多种 API 提供商(Lolicon API、Nekobot API、自定义 API)
20
+ - 🔍 灵活的参数筛选(大小、作者、标签、AI 作品排除等)
21
+ - 🛡️ 完善的参数验证和错误处理机制
22
+ - 🤖 支持 R18 内容控制
23
+ - 📊 智能参数适配(不同 API 自动使用对应支持的参数)
24
+ - 🎨 可配置的消息格式(集合回复或直接发送)
25
+ - 🖼️ 龙图提示
26
+ - 🏷️ 多标签搜索支持(Nekobot API)
27
+ - ⚡ 现代化的 TypeScript 架构设计
28
+
29
+ ## 📦 安装
30
+
31
+ ### 通过 npm 安装
32
+
33
+ ```bash
34
+ npm install @nenekusanagi/koishi-plugin-setu
35
+ ```
36
+
37
+ ### 通过 Koishi 插件市场
38
+
39
+ 在 Koishi 控制台的「插件市场」中搜索 `setu` 并安装。
40
+
41
+ ## ⚙️ 配置说明
42
+
43
+ ### API 提供商配置
44
+
45
+ 在插件设置中选择并配置 API 提供商:
46
+
47
+ #### 1. Lolicon API(默认)
48
+
49
+ - **API 地址**:默认 `https://api.lolicon.app/setu/v2`
50
+ - **默认图片大小**:regular(可选择 original、regular、small、thumb、mini)
51
+ - **R18 控制**:可开启/关闭限制级内容(开启后使用 `-r` 参数有效)
52
+
53
+ #### 2. Nekobot API
54
+
55
+ - **API 地址**:默认 `https://nekobot.xyz/api/image`
56
+ - **默认标签**:neko(无 `-t` 参数时使用)
57
+ - **⚠️ 警告**:本接口没有对限制级色图进行限制,用户可能会请求到限制级色图
58
+
59
+ #### 3. 自定义 API
60
+
61
+ - **API 地址**:用户自定义
62
+ - **参数支持**:禁用所有命令参数(由用户自行决定 API 格式)
63
+
64
+ ### 其他配置
65
+
66
+ - **通用参数**:
67
+ - 单日个人使用次数限制(默认 10 次)
68
+
69
+ - **机器人行为**:
70
+ - 使用集合回复(解决部分平台发图问题)
71
+ - 一次请求的图片数量(1-10,默认 1)
72
+
73
+ - **幽默**:
74
+ - 启用错误提示龙图
75
+ - 龙图图片地址(默认 GitHub 托管)
76
+
77
+ ## 🎮 使用方法
78
+
79
+ ### 基础指令
80
+
81
+ ```
82
+ setu # 获取随机色图
83
+ help setu # 查看帮助菜单
84
+ ```
85
+
86
+ ### 可用参数
87
+
88
+ | 参数 | 适用 API | 说明 | 示例 |
89
+ | :---------: | :------: | :-------------------------------: | :-----------------: |
90
+ | `-s <size>` | Lolicon | 设置图片大小 | `setu -s small` |
91
+ | `-r` | Lolicon | 获取限制级色图(需开启 R18 功能) | `setu -r` |
92
+ | `-t <tags>` | Nekobot | 指定标签(支持多标签,空格分隔) | `setu -t neko anal` |
93
+ | `-a <uid>` | Lolicon | 指定作者 UID 的作品 | `setu -a 123456` |
94
+ | `-A` | Lolicon | 排除 AI 作品 | `setu -A` |
95
+
96
+ ### 使用示例
97
+
98
+ ```bash
99
+ # 获取普通色图
100
+ setu
101
+
102
+ # 获取小图
103
+ setu -s small
104
+
105
+ # 获取限制级色图(需在配置中开启 R18)
106
+ setu -r
107
+
108
+ # 获取特定作者的作品
109
+ setu -a 123456
110
+
111
+ # 排除 AI 作品
112
+ setu -A
113
+
114
+ # 使用 Nekobot API 获取 neko 标签图片
115
+ setu -t neko
116
+
117
+ # 使用多个标签(Nekobot API)
118
+ setu -t neko anal
119
+ ```
120
+
121
+ ## 📋 API 参数支持矩阵
122
+
123
+ | 参数 | Lolicon API | Nekobot API | 自定义 API |
124
+ | :--------------: | :---------: | :---------: | :--------: |
125
+ | `-s/--size` | ✅ | ❌ | ❌ |
126
+ | `-r/--r18` | ✅ | ❌ | ❌ |
127
+ | `-t/--tags` | ❌ | ✅ | ❌ |
128
+ | `-a/--author` | ✅ | ❌ | ❌ |
129
+ | `-A/--excludeAI` | ✅ | ❌ | ❌ |
130
+
131
+ ## ⚠️ 重要提示
132
+
133
+ ### 网络要求
134
+
135
+ - 确保服务器支持 IPv6 连接(与 Lolicon API 通信需要)
136
+ - 网络不稳定时可能需要多次尝试
137
+
138
+ ### 使用限制
139
+
140
+ - **请在合法合规的环境下使用本插件**
141
+ - **不要在不支持的平台(如 QQ、Kook 等)启用限制级功能**
142
+ - **使用 R18 功能前请确保符合当地法律法规**
143
+ - **一切后果由用户自行承担,本插件仅展示技术实现**
144
+
145
+ ### 平台兼容性
146
+
147
+ - 部分平台可能对图片发送有限制,建议启用「使用集合回复」功能
148
+ - 发送限制级内容可能被平台 AI 识别并风控
149
+
150
+ ## 🔧 开发信息
151
+
152
+ ### 项目结构
153
+
154
+ ```
155
+ src/
156
+ ├── types/ # 类型定义
157
+ │ ├── config.ts # 配置类型
158
+ │ └── api.ts # API 类型
159
+ ├── services/ # 服务层
160
+ │ ├── api.ts # 主服务
161
+ │ └── providers/ # API 提供商
162
+ │ ├── lolicon.ts
163
+ │ ├── nekobot.ts
164
+ │ └── custom.ts
165
+ ├── utils/ # 工具函数
166
+ └── index.ts # 插件入口
167
+ ```
168
+
169
+ ### 技术栈
170
+
171
+ - **框架**:Koishi v4
172
+ - **语言**:TypeScript
173
+ - **架构**:模块化设计,支持多 API 提供商
174
+
175
+ ## 📚 参考资料
176
+
177
+ - [Koishi 官网](https://koishi.chat/)
178
+ - [Koishi GitHub](https://github.com/koishijs/koishi)
179
+ - [Lolicon API 文档](https://api.lolicon.app/#/setu)
180
+ - [Nekobot API 文档](https://nekobot.xyz/)
181
+
182
+ ## 🤝 贡献
183
+
184
+ 欢迎提交 Issue 和 Pull Request!
185
+
186
+ ## 📄 许可证
187
+
188
+ 本项目基于 [MIT](https://github.com/chitsanfei/koishi-plugin-setu/blob/master/LICENSE) 许可证开源。
189
+
190
+ ```
191
+ MIT License
192
+
193
+ Copyright (c) 2024 koishi-plugin-setu Contributors
194
+
195
+ Permission is hereby granted, free of charge, to any person obtaining a copy
196
+ of this software and associated documentation files (the "Software"), to deal
197
+ in the Software without restriction, including without limitation the rights
198
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
199
+ copies of the Software, and to permit persons to whom the Software is
200
+ furnished to do so, subject to the following conditions:
201
+
202
+ The above copyright notice and this permission notice shall be included in all
203
+ copies or substantial portions of the Software.
204
+
205
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
206
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
207
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
208
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
209
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
211
+ SOFTWARE.
212
+ ```
213
+
214
+ ## 🙏 致谢
215
+
216
+ - 感谢 [Koishi](https://github.com/koishijs/koishi) 团队提供的优秀框架
217
+ - 感谢前人 [Lipraty](https://github.com/Lipraty) 的开源项目
218
+ - 感谢所有使用和贡献本项目的开发者们
219
+
220
+ ---
221
+
222
+ <div align="center">
223
+ <b>⭐ 如果这个项目对你有帮助,请给它一个星标! ⭐</b>
224
+ </div>
package/lib/index.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ import { Context } from "koishi";
2
+ import { Config as ConfigInterface } from "./types/config";
3
+ export declare const name = "setu";
4
+ export declare const Config: import("schemastery")<Schemastery.ObjectS<{
5
+ provider: import("schemastery")<"lolicon" | "nekobot" | "custom", "lolicon" | "nekobot" | "custom">;
6
+ common: import("schemastery")<Schemastery.ObjectS<{
7
+ maxUsage: import("schemastery")<number, number>;
8
+ }>, Schemastery.ObjectT<{
9
+ maxUsage: import("schemastery")<number, number>;
10
+ }>>;
11
+ lolicon: import("schemastery")<Schemastery.ObjectS<{
12
+ allowR18: import("schemastery")<boolean, boolean>;
13
+ apiUrl: import("schemastery")<string, string>;
14
+ defaultPicSize: import("schemastery")<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
15
+ }>, Schemastery.ObjectT<{
16
+ allowR18: import("schemastery")<boolean, boolean>;
17
+ apiUrl: import("schemastery")<string, string>;
18
+ defaultPicSize: import("schemastery")<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
19
+ }>>;
20
+ nekobot: import("schemastery")<Schemastery.ObjectS<{
21
+ apiUrl: import("schemastery")<string, string>;
22
+ defaultTag: import("schemastery")<string, string>;
23
+ notice: import("schemastery")<string, string>;
24
+ }>, Schemastery.ObjectT<{
25
+ apiUrl: import("schemastery")<string, string>;
26
+ defaultTag: import("schemastery")<string, string>;
27
+ notice: import("schemastery")<string, string>;
28
+ }>>;
29
+ custom: import("schemastery")<Schemastery.ObjectS<{
30
+ apiUrl: import("schemastery")<string, string>;
31
+ }>, Schemastery.ObjectT<{
32
+ apiUrl: import("schemastery")<string, string>;
33
+ }>>;
34
+ behavior: import("schemastery")<Schemastery.ObjectS<{
35
+ useFigure: import("schemastery")<boolean, boolean>;
36
+ replyNumber: import("schemastery")<number, number>;
37
+ }>, Schemastery.ObjectT<{
38
+ useFigure: import("schemastery")<boolean, boolean>;
39
+ replyNumber: import("schemastery")<number, number>;
40
+ }>>;
41
+ humor: import("schemastery")<Schemastery.ObjectS<{
42
+ longPicWarning: import("schemastery")<boolean, boolean>;
43
+ longPicAddress: import("schemastery")<string, string>;
44
+ }>, Schemastery.ObjectT<{
45
+ longPicWarning: import("schemastery")<boolean, boolean>;
46
+ longPicAddress: import("schemastery")<string, string>;
47
+ }>>;
48
+ }>, Schemastery.ObjectT<{
49
+ provider: import("schemastery")<"lolicon" | "nekobot" | "custom", "lolicon" | "nekobot" | "custom">;
50
+ common: import("schemastery")<Schemastery.ObjectS<{
51
+ maxUsage: import("schemastery")<number, number>;
52
+ }>, Schemastery.ObjectT<{
53
+ maxUsage: import("schemastery")<number, number>;
54
+ }>>;
55
+ lolicon: import("schemastery")<Schemastery.ObjectS<{
56
+ allowR18: import("schemastery")<boolean, boolean>;
57
+ apiUrl: import("schemastery")<string, string>;
58
+ defaultPicSize: import("schemastery")<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
59
+ }>, Schemastery.ObjectT<{
60
+ allowR18: import("schemastery")<boolean, boolean>;
61
+ apiUrl: import("schemastery")<string, string>;
62
+ defaultPicSize: import("schemastery")<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
63
+ }>>;
64
+ nekobot: import("schemastery")<Schemastery.ObjectS<{
65
+ apiUrl: import("schemastery")<string, string>;
66
+ defaultTag: import("schemastery")<string, string>;
67
+ notice: import("schemastery")<string, string>;
68
+ }>, Schemastery.ObjectT<{
69
+ apiUrl: import("schemastery")<string, string>;
70
+ defaultTag: import("schemastery")<string, string>;
71
+ notice: import("schemastery")<string, string>;
72
+ }>>;
73
+ custom: import("schemastery")<Schemastery.ObjectS<{
74
+ apiUrl: import("schemastery")<string, string>;
75
+ }>, Schemastery.ObjectT<{
76
+ apiUrl: import("schemastery")<string, string>;
77
+ }>>;
78
+ behavior: import("schemastery")<Schemastery.ObjectS<{
79
+ useFigure: import("schemastery")<boolean, boolean>;
80
+ replyNumber: import("schemastery")<number, number>;
81
+ }>, Schemastery.ObjectT<{
82
+ useFigure: import("schemastery")<boolean, boolean>;
83
+ replyNumber: import("schemastery")<number, number>;
84
+ }>>;
85
+ humor: import("schemastery")<Schemastery.ObjectS<{
86
+ longPicWarning: import("schemastery")<boolean, boolean>;
87
+ longPicAddress: import("schemastery")<string, string>;
88
+ }>, Schemastery.ObjectT<{
89
+ longPicWarning: import("schemastery")<boolean, boolean>;
90
+ longPicAddress: import("schemastery")<string, string>;
91
+ }>>;
92
+ }>>;
93
+ export declare function apply(ctx: Context, config: ConfigInterface): void;
package/lib/index.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Config = exports.name = void 0;
4
+ exports.apply = apply;
5
+ const config_1 = require("./types/config");
6
+ const services_1 = require("./services");
7
+ const utils_1 = require("./utils");
8
+ const utils_2 = require("./utils");
9
+ exports.name = "setu";
10
+ exports.Config = config_1.ConfigSchema;
11
+ function apply(ctx, config) {
12
+ const logger = ctx.logger("setu");
13
+ // 加载多语言
14
+ ctx.i18n.define("zh", {
15
+ "commands.setu.description": "发一个瑟图",
16
+ "commands.setu.options.size": "设置图片大小",
17
+ "commands.setu.options.author": "指定作者 uid 的作品",
18
+ "commands.setu.options.excludeAI": "排除 AI 作品",
19
+ "commands.setu.options.r18": "检索 R18 作品,必须启用功能才能使用,参数为0或者1",
20
+ "commands.setu.messages.relax": "别急,正在给你找一个瑟图!",
21
+ "commands.setu.messages.error": "加载错误:{0}",
22
+ });
23
+ // 注册指令
24
+ ctx
25
+ .command("setu", "发一个瑟图")
26
+ .option("size", "-s <string>", {
27
+ fallback: (0, config_1.isLoliconConfig)(config)
28
+ ? config.lolicon.defaultPicSize
29
+ : "regular",
30
+ })
31
+ .option("r18", "-r", {
32
+ fallback: (0, config_1.isLoliconConfig)(config) ? config.lolicon.allowR18 : false,
33
+ })
34
+ .option("tags", "-t <string>")
35
+ .option("author", "-a <number>")
36
+ .option("excludeAI", "-A", { fallback: true })
37
+ .action(async ({ session, options }) => {
38
+ try {
39
+ // 检查配置是否有效
40
+ if (!(0, config_1.hasValidConfig)(config)) {
41
+ logger.warn("API 提供商未配置或配置不完整,请在插件设置中选择并配置 API 提供商");
42
+ if (config.humor.longPicWarning) {
43
+ return `<image url="${config.humor.longPicAddress}"/>`;
44
+ }
45
+ return "API 提供商未配置或配置不完整,请在插件设置中选择并配置 API 提供商";
46
+ }
47
+ // 初始化服务
48
+ const setuService = new services_1.SetuService(ctx, config);
49
+ // 获取默认图片大小(与 fallback 保持一致)
50
+ const defaultPicSize = (0, config_1.isLoliconConfig)(config)
51
+ ? config.lolicon.defaultPicSize
52
+ : "regular";
53
+ // 获取 R18 允许状态(与 fallback 保持一致)
54
+ const allowR18 = (0, config_1.isLoliconConfig)(config)
55
+ ? config.lolicon.allowR18
56
+ : false;
57
+ // 标记用户输入的参数(如果值不等于 fallback,说明是用户输入的)
58
+ const userInput = {
59
+ _tags: options.tags !== undefined, // tags 没有 fallback,所以只要有值就是用户输入
60
+ _author: options.author !== undefined,
61
+ _size: options.size !== defaultPicSize,
62
+ _r18: options.r18 !== allowR18,
63
+ _excludeAI: options.excludeAI !== true,
64
+ };
65
+ // 验证参数支持
66
+ const paramError = (0, config_1.validateParameters)(config.provider, userInput);
67
+ if (paramError) {
68
+ return paramError;
69
+ }
70
+ // 验证参数
71
+ const size = (0, utils_2.validatePicSize)(options.size)
72
+ ? options.size
73
+ : defaultPicSize;
74
+ const num = (0, utils_2.validateReplyNumber)(config.behavior.replyNumber)
75
+ ? config.behavior.replyNumber
76
+ : 1;
77
+ const r18 = options.r18 === true ? 1 : 0;
78
+ // 处理标签(空格分隔)
79
+ const tags = options.tags ? options.tags.split(" ") : [];
80
+ // 构建查询选项
81
+ const queryOptions = {
82
+ size,
83
+ num,
84
+ r18,
85
+ tags,
86
+ author: options.author,
87
+ excludeAI: options.excludeAI,
88
+ };
89
+ // 发送请求
90
+ const response = await setuService.getSetu(queryOptions);
91
+ // 检查响应
92
+ if (!response.data || response.data.length === 0) {
93
+ if (config.humor.longPicWarning) {
94
+ return `<image url="${config.humor.longPicAddress}"/>`;
95
+ }
96
+ return session.text(".error", [
97
+ response.error || "没有找到符合条件的图片",
98
+ ]);
99
+ }
100
+ // 发送加载提示
101
+ await session.send(session.text(".relax"));
102
+ // 根据配置选择消息格式
103
+ if (config.behavior.useFigure) {
104
+ return (0, utils_1.createFigureMessage)(session, response.data, size);
105
+ }
106
+ else {
107
+ return (0, utils_1.createImageMessage)(response.data, size);
108
+ }
109
+ }
110
+ catch (error) {
111
+ logger.error("获取色图失败:", error);
112
+ // 错误处理
113
+ if (config.humor.longPicWarning) {
114
+ return `<image url="${config.humor.longPicAddress}"/>`;
115
+ }
116
+ else if (error.code === "EHOSTUNREACH") {
117
+ return "与 API 的交互发生问题,请重试指令或排查服务器网络";
118
+ }
119
+ else {
120
+ return session.text(".error", [error.message || "未知错误"]);
121
+ }
122
+ }
123
+ });
124
+ // 记录初始化信息
125
+ logger.info("Setu 插件初始化完成");
126
+ }
@@ -0,0 +1,12 @@
1
+ import { Context } from "koishi";
2
+ import { Config } from "../types/config";
3
+ import { SetuOptions, LoliconResponse } from "../types/api";
4
+ export declare class SetuService {
5
+ private ctx;
6
+ private config;
7
+ private provider;
8
+ constructor(ctx: Context, config: Config);
9
+ private createProvider;
10
+ getSetu(options: SetuOptions): Promise<LoliconResponse>;
11
+ getProviderName(): string;
12
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SetuService = void 0;
4
+ const config_1 = require("../types/config");
5
+ const lolicon_1 = require("./providers/lolicon");
6
+ const custom_1 = require("./providers/custom");
7
+ const nekobot_1 = require("./providers/nekobot");
8
+ class SetuService {
9
+ constructor(ctx, config) {
10
+ this.ctx = ctx;
11
+ this.config = config;
12
+ this.provider = this.createProvider(this.config);
13
+ }
14
+ createProvider(config) {
15
+ if ((0, config_1.isLoliconConfig)(config)) {
16
+ return new lolicon_1.LoliconProvider(config.lolicon.apiUrl, config.lolicon.allowR18);
17
+ }
18
+ else if ((0, config_1.isCustomConfig)(config)) {
19
+ return new custom_1.CustomProvider(config.custom.apiUrl);
20
+ }
21
+ else if ((0, config_1.isNekobotConfig)(config)) {
22
+ return new nekobot_1.NekobotProvider(config.nekobot.apiUrl, config.nekobot.defaultTag, this.ctx);
23
+ }
24
+ else {
25
+ throw new Error("未选择 API 提供商");
26
+ }
27
+ }
28
+ async getSetu(options) {
29
+ try {
30
+ return await this.provider.getSetu(options);
31
+ }
32
+ catch (error) {
33
+ const logger = this.ctx.logger("setu");
34
+ logger.error(`获取色图失败:`, error);
35
+ throw error;
36
+ }
37
+ }
38
+ getProviderName() {
39
+ return this.provider.name;
40
+ }
41
+ }
42
+ exports.SetuService = SetuService;
@@ -0,0 +1,2 @@
1
+ export * from "./api";
2
+ export * from "./providers";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./api"), exports);
18
+ __exportStar(require("./providers"), exports);
@@ -0,0 +1,7 @@
1
+ import { ApiProvider, SetuOptions, LoliconResponse } from "../../types/api";
2
+ export declare class CustomProvider implements ApiProvider {
3
+ private apiUrl;
4
+ readonly name = "custom";
5
+ constructor(apiUrl: string);
6
+ getSetu(options: SetuOptions): Promise<LoliconResponse>;
7
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CustomProvider = void 0;
4
+ class CustomProvider {
5
+ constructor(apiUrl) {
6
+ this.apiUrl = apiUrl;
7
+ this.name = "custom";
8
+ }
9
+ async getSetu(options) {
10
+ // 自定义 API 的实现
11
+ // 这里需要根据具体的自定义 API 规范来实现
12
+ // 目前只是一个占位实现
13
+ throw new Error("自定义 API 尚未实现");
14
+ }
15
+ }
16
+ exports.CustomProvider = CustomProvider;
@@ -0,0 +1,3 @@
1
+ import { Config } from '../../types/config';
2
+ import { ApiProvider } from '../../types/api';
3
+ export declare function createApiProvider(config: Config): ApiProvider;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createApiProvider = createApiProvider;
4
+ const lolicon_1 = require("./lolicon");
5
+ const custom_1 = require("./custom");
6
+ function createApiProvider(config) {
7
+ switch (config.provider) {
8
+ case 'lolicon':
9
+ const loliconUrl = config.imageConfig.loliconApiUrl || 'https://api.lolicon.app/setu/v2';
10
+ return new lolicon_1.LoliconProvider(loliconUrl);
11
+ case 'custom':
12
+ const customUrl = config.imageConfig.customApiUrl;
13
+ if (!customUrl) {
14
+ throw new Error('自定义 API 地址未配置');
15
+ }
16
+ return new custom_1.CustomProvider(customUrl, config.imageConfig.customApiProxy);
17
+ default:
18
+ throw new Error(`未知的 API 提供商: ${config.provider}`);
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./lolicon";
2
+ export * from "./custom";
3
+ export * from "./nekobot";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./lolicon"), exports);
18
+ __exportStar(require("./custom"), exports);
19
+ __exportStar(require("./nekobot"), exports);
@@ -0,0 +1,8 @@
1
+ import { ApiProvider, SetuOptions, LoliconResponse } from "../../types/api";
2
+ export declare class LoliconProvider implements ApiProvider {
3
+ private apiUrl;
4
+ private allowR18;
5
+ readonly name = "lolicon";
6
+ constructor(apiUrl: string, allowR18: boolean);
7
+ getSetu(options: SetuOptions): Promise<LoliconResponse>;
8
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoliconProvider = void 0;
4
+ class LoliconProvider {
5
+ constructor(apiUrl, allowR18) {
6
+ this.apiUrl = apiUrl;
7
+ this.allowR18 = allowR18;
8
+ this.name = "lolicon";
9
+ }
10
+ async getSetu(options) {
11
+ // 检查 R18 请求是否被允许
12
+ if (options.r18 && options.r18 > 0 && !this.allowR18) {
13
+ return {
14
+ error: "未开启 R18 内容功能,无法获取限制级色图",
15
+ data: [],
16
+ };
17
+ }
18
+ const response = await fetch(this.apiUrl, {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/json",
22
+ },
23
+ body: JSON.stringify({
24
+ r18: options.r18 || 0,
25
+ num: options.num || 1,
26
+ size: options.size || "regular",
27
+ proxy: options.proxy,
28
+ author: options.author,
29
+ excludeAI: options.excludeAI,
30
+ }),
31
+ });
32
+ if (!response.ok) {
33
+ throw new Error(`HTTP error! status: ${response.status}`);
34
+ }
35
+ return await response.json();
36
+ }
37
+ }
38
+ exports.LoliconProvider = LoliconProvider;
@@ -0,0 +1,10 @@
1
+ import { ApiProvider, SetuOptions, LoliconResponse } from "../../types/api";
2
+ import { Context } from "koishi";
3
+ export declare class NekobotProvider implements ApiProvider {
4
+ private apiUrl;
5
+ private defaultTag;
6
+ private ctx;
7
+ readonly name = "nekobot";
8
+ constructor(apiUrl: string, defaultTag: string, ctx: Context);
9
+ getSetu(options: SetuOptions): Promise<LoliconResponse>;
10
+ }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NekobotProvider = void 0;
4
+ class NekobotProvider {
5
+ constructor(apiUrl, defaultTag, ctx) {
6
+ this.apiUrl = apiUrl;
7
+ this.defaultTag = defaultTag;
8
+ this.ctx = ctx;
9
+ this.name = "nekobot";
10
+ }
11
+ async getSetu(options) {
12
+ // Nekobot API 只支持 -t 参数,支持多标签(空格分隔)
13
+ const tags = options.tags && options.tags.length > 0
14
+ ? options.tags.join(" ")
15
+ : this.defaultTag;
16
+ const apiUrl = `${this.apiUrl}?type=${encodeURIComponent(tags)}`;
17
+ try {
18
+ const data = await this.ctx.http.get(apiUrl);
19
+ // Nekobot API 返回的数据结构:{ success: true, message: 'https://...' }
20
+ if (!data.success || !data.message) {
21
+ return {
22
+ error: "获取图片失败:API 返回数据异常",
23
+ data: [],
24
+ };
25
+ }
26
+ return {
27
+ data: [
28
+ {
29
+ pid: 0,
30
+ p: 0,
31
+ uid: 0,
32
+ title: "",
33
+ author: "",
34
+ url: data.message,
35
+ r18: false,
36
+ width: 0,
37
+ height: 0,
38
+ tags: [tags],
39
+ ext: "jpg",
40
+ aiType: 0,
41
+ uploadDate: 0,
42
+ urls: {
43
+ original: data.message,
44
+ regular: data.message,
45
+ small: data.message,
46
+ thumb: data.message,
47
+ mini: data.message,
48
+ },
49
+ },
50
+ ],
51
+ };
52
+ }
53
+ catch (error) {
54
+ return {
55
+ error: error instanceof Error ? error.message : "未知错误",
56
+ data: [],
57
+ };
58
+ }
59
+ }
60
+ }
61
+ exports.NekobotProvider = NekobotProvider;
@@ -0,0 +1,39 @@
1
+ export interface SetuData {
2
+ pid: number;
3
+ p: number;
4
+ uid: number;
5
+ title: string;
6
+ author: string;
7
+ url: string;
8
+ r18: boolean;
9
+ width: number;
10
+ height: number;
11
+ tags: string[];
12
+ ext: string;
13
+ aiType: number;
14
+ uploadDate: number;
15
+ urls: {
16
+ original: string;
17
+ regular: string;
18
+ small: string;
19
+ thumb: string;
20
+ mini: string;
21
+ };
22
+ }
23
+ export interface LoliconResponse {
24
+ error?: string;
25
+ data: SetuData[];
26
+ }
27
+ export interface ApiProvider {
28
+ name: string;
29
+ getSetu(options: SetuOptions): Promise<LoliconResponse>;
30
+ }
31
+ export interface SetuOptions {
32
+ r18?: number;
33
+ num?: number;
34
+ size?: "original" | "regular" | "small" | "thumb" | "mini";
35
+ proxy?: string;
36
+ author?: number;
37
+ excludeAI?: boolean;
38
+ tags?: string[];
39
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,159 @@
1
+ import { Schema } from "koishi";
2
+ export type ApiProviderType = "lolicon" | "custom" | "nekobot";
3
+ export interface Config {
4
+ provider: "lolicon" | "custom" | "nekobot";
5
+ common: {
6
+ maxUsage: number;
7
+ };
8
+ lolicon: {
9
+ allowR18: boolean;
10
+ apiUrl: string;
11
+ defaultPicSize: "original" | "regular" | "small" | "thumb" | "mini";
12
+ };
13
+ custom: {
14
+ apiUrl: string;
15
+ };
16
+ nekobot: {
17
+ apiUrl: string;
18
+ defaultTag: string;
19
+ notice: string;
20
+ };
21
+ behavior: {
22
+ useFigure: boolean;
23
+ replyNumber: number;
24
+ };
25
+ humor: {
26
+ longPicWarning: boolean;
27
+ longPicAddress: string;
28
+ };
29
+ }
30
+ export interface CommandOptions {
31
+ maxUsage?: number;
32
+ }
33
+ export declare function isLoliconConfig(config: Config): config is Config & {
34
+ provider: "lolicon";
35
+ lolicon: {
36
+ allowR18: boolean;
37
+ apiUrl: string;
38
+ defaultPicSize: "original" | "regular" | "small" | "thumb" | "mini";
39
+ };
40
+ };
41
+ export declare function isCustomConfig(config: Config): config is Config & {
42
+ provider: "custom";
43
+ custom: {
44
+ apiUrl: string;
45
+ };
46
+ };
47
+ export declare function isNekobotConfig(config: Config): config is Config & {
48
+ provider: "nekobot";
49
+ nekobot: {
50
+ apiUrl: string;
51
+ defaultTag: string;
52
+ notice: string;
53
+ };
54
+ };
55
+ export declare function hasValidConfig(config: Config): boolean;
56
+ export declare const APIParameterSupport: {
57
+ lolicon: {
58
+ name: string;
59
+ supportedParams: string[];
60
+ };
61
+ nekobot: {
62
+ name: string;
63
+ supportedParams: string[];
64
+ };
65
+ custom: {
66
+ name: string;
67
+ supportedParams: any[];
68
+ };
69
+ };
70
+ export declare function validateParameters(provider: string, options: any): string | null;
71
+ export declare const ConfigSchema: Schema<Schemastery.ObjectS<{
72
+ provider: Schema<"lolicon" | "nekobot" | "custom", "lolicon" | "nekobot" | "custom">;
73
+ common: Schema<Schemastery.ObjectS<{
74
+ maxUsage: Schema<number, number>;
75
+ }>, Schemastery.ObjectT<{
76
+ maxUsage: Schema<number, number>;
77
+ }>>;
78
+ lolicon: Schema<Schemastery.ObjectS<{
79
+ allowR18: Schema<boolean, boolean>;
80
+ apiUrl: Schema<string, string>;
81
+ defaultPicSize: Schema<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
82
+ }>, Schemastery.ObjectT<{
83
+ allowR18: Schema<boolean, boolean>;
84
+ apiUrl: Schema<string, string>;
85
+ defaultPicSize: Schema<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
86
+ }>>;
87
+ nekobot: Schema<Schemastery.ObjectS<{
88
+ apiUrl: Schema<string, string>;
89
+ defaultTag: Schema<string, string>;
90
+ notice: Schema<string, string>;
91
+ }>, Schemastery.ObjectT<{
92
+ apiUrl: Schema<string, string>;
93
+ defaultTag: Schema<string, string>;
94
+ notice: Schema<string, string>;
95
+ }>>;
96
+ custom: Schema<Schemastery.ObjectS<{
97
+ apiUrl: Schema<string, string>;
98
+ }>, Schemastery.ObjectT<{
99
+ apiUrl: Schema<string, string>;
100
+ }>>;
101
+ behavior: Schema<Schemastery.ObjectS<{
102
+ useFigure: Schema<boolean, boolean>;
103
+ replyNumber: Schema<number, number>;
104
+ }>, Schemastery.ObjectT<{
105
+ useFigure: Schema<boolean, boolean>;
106
+ replyNumber: Schema<number, number>;
107
+ }>>;
108
+ humor: Schema<Schemastery.ObjectS<{
109
+ longPicWarning: Schema<boolean, boolean>;
110
+ longPicAddress: Schema<string, string>;
111
+ }>, Schemastery.ObjectT<{
112
+ longPicWarning: Schema<boolean, boolean>;
113
+ longPicAddress: Schema<string, string>;
114
+ }>>;
115
+ }>, Schemastery.ObjectT<{
116
+ provider: Schema<"lolicon" | "nekobot" | "custom", "lolicon" | "nekobot" | "custom">;
117
+ common: Schema<Schemastery.ObjectS<{
118
+ maxUsage: Schema<number, number>;
119
+ }>, Schemastery.ObjectT<{
120
+ maxUsage: Schema<number, number>;
121
+ }>>;
122
+ lolicon: Schema<Schemastery.ObjectS<{
123
+ allowR18: Schema<boolean, boolean>;
124
+ apiUrl: Schema<string, string>;
125
+ defaultPicSize: Schema<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
126
+ }>, Schemastery.ObjectT<{
127
+ allowR18: Schema<boolean, boolean>;
128
+ apiUrl: Schema<string, string>;
129
+ defaultPicSize: Schema<"original" | "regular" | "small" | "thumb" | "mini", "original" | "regular" | "small" | "thumb" | "mini">;
130
+ }>>;
131
+ nekobot: Schema<Schemastery.ObjectS<{
132
+ apiUrl: Schema<string, string>;
133
+ defaultTag: Schema<string, string>;
134
+ notice: Schema<string, string>;
135
+ }>, Schemastery.ObjectT<{
136
+ apiUrl: Schema<string, string>;
137
+ defaultTag: Schema<string, string>;
138
+ notice: Schema<string, string>;
139
+ }>>;
140
+ custom: Schema<Schemastery.ObjectS<{
141
+ apiUrl: Schema<string, string>;
142
+ }>, Schemastery.ObjectT<{
143
+ apiUrl: Schema<string, string>;
144
+ }>>;
145
+ behavior: Schema<Schemastery.ObjectS<{
146
+ useFigure: Schema<boolean, boolean>;
147
+ replyNumber: Schema<number, number>;
148
+ }>, Schemastery.ObjectT<{
149
+ useFigure: Schema<boolean, boolean>;
150
+ replyNumber: Schema<number, number>;
151
+ }>>;
152
+ humor: Schema<Schemastery.ObjectS<{
153
+ longPicWarning: Schema<boolean, boolean>;
154
+ longPicAddress: Schema<string, string>;
155
+ }>, Schemastery.ObjectT<{
156
+ longPicWarning: Schema<boolean, boolean>;
157
+ longPicAddress: Schema<string, string>;
158
+ }>>;
159
+ }>>;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigSchema = exports.APIParameterSupport = void 0;
4
+ exports.isLoliconConfig = isLoliconConfig;
5
+ exports.isCustomConfig = isCustomConfig;
6
+ exports.isNekobotConfig = isNekobotConfig;
7
+ exports.hasValidConfig = hasValidConfig;
8
+ exports.validateParameters = validateParameters;
9
+ const koishi_1 = require("koishi");
10
+ function isLoliconConfig(config) {
11
+ return config.provider === "lolicon";
12
+ }
13
+ function isCustomConfig(config) {
14
+ return config.provider === "custom";
15
+ }
16
+ function isNekobotConfig(config) {
17
+ return config.provider === "nekobot";
18
+ }
19
+ function hasValidConfig(config) {
20
+ if (config.provider === "lolicon") {
21
+ return !!config.lolicon?.apiUrl;
22
+ }
23
+ else if (config.provider === "custom") {
24
+ return !!config.custom?.apiUrl;
25
+ }
26
+ else if (config.provider === "nekobot") {
27
+ return !!config.nekobot?.apiUrl;
28
+ }
29
+ return false;
30
+ }
31
+ // 定义每个 API 支持的参数
32
+ exports.APIParameterSupport = {
33
+ lolicon: {
34
+ name: "Lolicon API",
35
+ supportedParams: ["size", "r18", "num", "author", "excludeAI"],
36
+ },
37
+ nekobot: {
38
+ name: "Nekobot API",
39
+ supportedParams: ["tags"],
40
+ },
41
+ custom: {
42
+ name: "自定义 API",
43
+ supportedParams: [], // 自定义 API 由用户自己决定
44
+ },
45
+ };
46
+ function validateParameters(provider, options) {
47
+ // 自定义 API 禁用所有参数
48
+ if (provider === "custom") {
49
+ const unsupportedParams = [];
50
+ if (options._tags)
51
+ unsupportedParams.push("-t/--tags");
52
+ if (options._author)
53
+ unsupportedParams.push("-a/--author");
54
+ if (options._excludeAI)
55
+ unsupportedParams.push("-A/--excludeAI");
56
+ if (options._size)
57
+ unsupportedParams.push("-s/--size");
58
+ if (options._r18)
59
+ unsupportedParams.push("-r/--r18");
60
+ if (unsupportedParams.length > 0) {
61
+ return `(自定义 API)该接口不支持任何参数,请勿使用:${unsupportedParams.join(", ")}`;
62
+ }
63
+ return null;
64
+ }
65
+ const support = exports.APIParameterSupport[provider];
66
+ if (!support)
67
+ return null;
68
+ const unsupportedParams = [];
69
+ // 检查所有选项参数(只有明确输入的参数才验证,前缀_表示用户输入)
70
+ if (options._tags && provider !== "nekobot") {
71
+ unsupportedParams.push("-t/--tags");
72
+ }
73
+ if (options._author && provider === "nekobot") {
74
+ unsupportedParams.push("-a/--author");
75
+ }
76
+ if (options._excludeAI && provider === "nekobot") {
77
+ unsupportedParams.push("-A/--excludeAI");
78
+ }
79
+ if (options._size && provider === "nekobot") {
80
+ unsupportedParams.push("-s/--size");
81
+ }
82
+ if (options._r18 && provider === "nekobot") {
83
+ unsupportedParams.push("-r/--r18");
84
+ }
85
+ if (unsupportedParams.length > 0) {
86
+ return `(${support.name})该接口不支持的参数:${unsupportedParams.join(", ")}`;
87
+ }
88
+ return null;
89
+ }
90
+ // 完整配置 Schema
91
+ exports.ConfigSchema = koishi_1.Schema.object({
92
+ // 基础设置
93
+ provider: koishi_1.Schema.union([
94
+ koishi_1.Schema.const("lolicon").description("Lolicon API"),
95
+ koishi_1.Schema.const("nekobot").description("Nekobot API"),
96
+ koishi_1.Schema.const("custom").description("自定义 API"),
97
+ ])
98
+ .default("lolicon")
99
+ .description("API 提供商"),
100
+ // 通用参数
101
+ common: koishi_1.Schema.object({
102
+ maxUsage: koishi_1.Schema.number()
103
+ .default(10)
104
+ .step(1)
105
+ .description("单日个人使用次数限制"),
106
+ }).description("通用参数"),
107
+ // Lolicon 专用参数
108
+ lolicon: koishi_1.Schema.object({
109
+ allowR18: koishi_1.Schema.boolean()
110
+ .default(false)
111
+ .description("是否允许 R18 内容(请谨慎使用)"),
112
+ apiUrl: koishi_1.Schema.string()
113
+ .role("link")
114
+ .default("https://api.lolicon.app/setu/v2")
115
+ .description("API 地址"),
116
+ defaultPicSize: koishi_1.Schema.union([
117
+ koishi_1.Schema.const("original").description("原图(不推荐)"),
118
+ koishi_1.Schema.const("regular").description("普通"),
119
+ koishi_1.Schema.const("small").description("小图"),
120
+ koishi_1.Schema.const("thumb").description("极小图"),
121
+ koishi_1.Schema.const("mini").description("迷你图"),
122
+ ])
123
+ .description("默认图片大小")
124
+ .default("regular"),
125
+ }).description("Lolicon 参数"),
126
+ // Nekobot 专用参数
127
+ nekobot: koishi_1.Schema.object({
128
+ apiUrl: koishi_1.Schema.string()
129
+ .role("link")
130
+ .default("https://nekobot.xyz/api/image")
131
+ .description("API 地址"),
132
+ defaultTag: koishi_1.Schema.string()
133
+ .default("neko")
134
+ .description("默认标签(如果没有指定 -t 参数)"),
135
+ notice: koishi_1.Schema.string()
136
+ .default("")
137
+ .description("⚠️ 警告:本接口没有对限制级色图进行限制,用户可能会请求到限制级色图"),
138
+ }).description("Nekobot 参数"),
139
+ // 自定义 API 参数
140
+ custom: koishi_1.Schema.object({
141
+ apiUrl: koishi_1.Schema.string()
142
+ .role("link")
143
+ .default("")
144
+ .description("自定义 API 地址"),
145
+ }).description("自定义 API 参数"),
146
+ // 机器人行为
147
+ behavior: koishi_1.Schema.object({
148
+ useFigure: koishi_1.Schema.boolean()
149
+ .default(false)
150
+ .description("使用集合回复(解决部分平台发图问题)"),
151
+ replyNumber: koishi_1.Schema.number()
152
+ .default(1)
153
+ .max(10)
154
+ .min(1)
155
+ .step(1)
156
+ .description("一次请求的图片数量(1-10)"),
157
+ }).description("机器人行为"),
158
+ // 幽默
159
+ humor: koishi_1.Schema.object({
160
+ longPicWarning: koishi_1.Schema.boolean()
161
+ .default(false)
162
+ .description("启用错误提示龙图"),
163
+ longPicAddress: koishi_1.Schema.string()
164
+ .default("https://raw.githubusercontent.com/chitsanfei/koishi-plugin-setu/master/assets/long.jpg")
165
+ .description("龙图图片地址"),
166
+ }).description("幽默"),
167
+ });
@@ -0,0 +1,2 @@
1
+ export * from "./message";
2
+ export * from "./validation";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./message"), exports);
18
+ __exportStar(require("./validation"), exports);
@@ -0,0 +1,5 @@
1
+ import { Session } from "koishi";
2
+ import { SetuData } from "../types/api";
3
+ export declare function createFigureMessage(session: Session, setuData: SetuData[], size: string): any;
4
+ export declare function createImageMessage(setuData: SetuData[], size: string): string;
5
+ export declare function formatSetuInfo(data: SetuData): string;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFigureMessage = createFigureMessage;
4
+ exports.createImageMessage = createImageMessage;
5
+ exports.formatSetuInfo = formatSetuInfo;
6
+ const koishi_1 = require("koishi");
7
+ function createFigureMessage(session, setuData, size) {
8
+ const attrs = {
9
+ userId: session.userId,
10
+ nickname: session.author?.nickname || session.username,
11
+ };
12
+ const result = (0, koishi_1.h)("figure");
13
+ for (const data of setuData) {
14
+ result.children.push((0, koishi_1.h)("message", attrs, String(data.pid)));
15
+ result.children.push((0, koishi_1.h)("image", { url: data.urls[size] }));
16
+ }
17
+ return result;
18
+ }
19
+ function createImageMessage(setuData, size) {
20
+ let reply = "";
21
+ for (const data of setuData) {
22
+ reply += `<image url="${data.urls[size]}"/>`;
23
+ }
24
+ return reply;
25
+ }
26
+ function formatSetuInfo(data) {
27
+ return `标题: ${data.title}\n作者: ${data.author}\nPID: ${data.pid}\n标签: ${data.tags.join(", ")}`;
28
+ }
@@ -0,0 +1,3 @@
1
+ export declare function validatePicSize(size: string): size is "original" | "regular" | "small" | "thumb" | "mini";
2
+ export declare function validateReplyNumber(num: number): boolean;
3
+ export declare function validateR18Value(r18: number | undefined, allowR18: boolean): number;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validatePicSize = validatePicSize;
4
+ exports.validateReplyNumber = validateReplyNumber;
5
+ exports.validateR18Value = validateR18Value;
6
+ function validatePicSize(size) {
7
+ return ["original", "regular", "small", "thumb", "mini"].includes(size);
8
+ }
9
+ function validateReplyNumber(num) {
10
+ return num >= 1 && num <= 10;
11
+ }
12
+ function validateR18Value(r18, allowR18) {
13
+ if (!allowR18)
14
+ return 0;
15
+ return r18 || 0;
16
+ }
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@nenekusanagi/koishi-plugin-setu",
3
+ "description": "A simple setu program powered by Koishi.",
4
+ "version": "1.1.0",
5
+ "contributors": [
6
+ "NeneKusanagi <nenekusa.sekai@gmail.com>"
7
+ ],
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/chitsanfei/koishi-plugin-setu.git"
11
+ },
12
+ "koishi": {
13
+ "description": {
14
+ "en": "Funny anime image plugin based on the previous work.",
15
+ "zh": "基于前人做了小修改的好玩的图片插件。"
16
+ },
17
+ "locales": [
18
+ "zh"
19
+ ]
20
+ },
21
+ "main": "lib/index.js",
22
+ "typings": "lib/index.d.ts",
23
+ "files": [
24
+ "lib",
25
+ "dist"
26
+ ],
27
+ "license": "MIT",
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "dev": "koishi dev",
33
+ "build": "tsc",
34
+ "start": "koishi start",
35
+ "test": "echo \"No tests yet\"",
36
+ "pre-commit": "lint-staged",
37
+ "format": "prettier --write \"**/*.{ts,js,json,md,yml,yaml}\"",
38
+ "lint": "prettier --check \"**/*.{ts,js,json,md,yml,yaml}\""
39
+ },
40
+ "lint-staged": {
41
+ "*.{ts,js}": [
42
+ "prettier --write",
43
+ "git add"
44
+ ],
45
+ "*.{json,md,yml,yaml}": [
46
+ "prettier --write",
47
+ "git add"
48
+ ]
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.10.0",
52
+ "husky": "^9.1.7",
53
+ "lint-staged": "^16.2.7",
54
+ "prettier": "^3.7.4",
55
+ "typescript": "^5.3.0"
56
+ },
57
+ "keywords": [
58
+ "chatbot",
59
+ "koishi",
60
+ "plugin"
61
+ ],
62
+ "peerDependencies": {
63
+ "koishi": "^4.12.2"
64
+ },
65
+ "dependencies": {
66
+ "@nenekusanagi/koishi-plugin-setu": "file:"
67
+ }
68
+ }