koishi-plugin-meme-upload-114 0.0.1 → 0.0.2
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 +1 -0
- package/lib/index.js +77 -33
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface Config {
|
|
|
11
11
|
defaultTimeout: number;
|
|
12
12
|
autoWithdrawSuccess: boolean;
|
|
13
13
|
successWithdrawTime: number;
|
|
14
|
+
associations: string[][];
|
|
14
15
|
}
|
|
15
16
|
export declare const Config: Schema<Config>;
|
|
16
17
|
export declare function apply(ctx: Context, config: Config): void;
|
package/lib/index.js
CHANGED
|
@@ -45,7 +45,9 @@ var Config = import_koishi.Schema.object({
|
|
|
45
45
|
rootDir: import_koishi.Schema.path({ filters: ["directory"], allowCreate: true }).default("data/images").description("图片存储的根目录"),
|
|
46
46
|
defaultTimeout: import_koishi.Schema.number().default(1e4).description("创建文件夹确认的等待时间(毫秒)"),
|
|
47
47
|
autoWithdrawSuccess: import_koishi.Schema.boolean().default(true).description("是否自动撤回“上传成功”的提示"),
|
|
48
|
-
successWithdrawTime: import_koishi.Schema.number().default(1e4).description("上传成功提示的撤回延迟(毫秒)")
|
|
48
|
+
successWithdrawTime: import_koishi.Schema.number().default(1e4).description("上传成功提示的撤回延迟(毫秒)"),
|
|
49
|
+
// === 新增配置项 ===
|
|
50
|
+
associations: import_koishi.Schema.array(import_koishi.Schema.array(import_koishi.Schema.string())).default([]).description('文件夹关联/分组设置。\n点击添加一行,然后在行内添加多个文件夹名。\n例如:["1", "2"] 表示发送 1 或 2 时,会从这两个文件夹的所有图片中随机选取。')
|
|
49
51
|
});
|
|
50
52
|
function apply(ctx, config) {
|
|
51
53
|
const root = path.resolve(ctx.baseDir, config.rootDir);
|
|
@@ -57,27 +59,30 @@ function apply(ctx, config) {
|
|
|
57
59
|
<html>
|
|
58
60
|
<head>
|
|
59
61
|
<style>
|
|
60
|
-
body { font-family: sans-serif; padding: 20px; background: transparent; width: fit-content; }
|
|
62
|
+
body { font-family: "Microsoft YaHei", "SimHei", sans-serif; padding: 20px; background: transparent; width: fit-content; }
|
|
61
63
|
.container {
|
|
62
64
|
display: flex;
|
|
63
65
|
align-items: flex-start;
|
|
64
|
-
max-width:
|
|
66
|
+
max-width: 450px;
|
|
67
|
+
min-width: 260px;
|
|
65
68
|
background: #ffffff;
|
|
66
|
-
padding:
|
|
69
|
+
padding: 16px 22px;
|
|
67
70
|
border-radius: 12px;
|
|
68
|
-
box-shadow: 0 4px
|
|
71
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
72
|
+
border: 1px solid #f2f2f2;
|
|
69
73
|
}
|
|
70
74
|
.avatar {
|
|
71
75
|
width: 50px;
|
|
72
76
|
height: 50px;
|
|
73
77
|
border-radius: 50%;
|
|
74
|
-
margin-right:
|
|
78
|
+
margin-right: 16px;
|
|
75
79
|
border: 1px solid #eee;
|
|
76
80
|
flex-shrink: 0;
|
|
81
|
+
object-fit: cover;
|
|
77
82
|
}
|
|
78
|
-
.content-box { display: flex; flex-direction: column; }
|
|
79
|
-
.name { font-size:
|
|
80
|
-
.text { font-size:
|
|
83
|
+
.content-box { display: flex; flex-direction: column; justify-content: center; min-height: 50px; }
|
|
84
|
+
.name { font-size: 15px; color: #888; margin-bottom: 6px; font-weight: bold; }
|
|
85
|
+
.text { font-size: 18px; color: #333; line-height: 1.5; word-wrap: break-word; white-space: pre-wrap; }
|
|
81
86
|
</style>
|
|
82
87
|
</head>
|
|
83
88
|
<body>
|
|
@@ -92,32 +97,58 @@ function apply(ctx, config) {
|
|
|
92
97
|
</html>
|
|
93
98
|
`;
|
|
94
99
|
}, "generateQuoteHtml");
|
|
100
|
+
const getDisplayName = /* @__PURE__ */ __name(async (session, quote) => {
|
|
101
|
+
const userId = quote.user?.id || quote.author?.id;
|
|
102
|
+
const guildId = session.guildId || quote.guildId;
|
|
103
|
+
if (guildId && userId) {
|
|
104
|
+
try {
|
|
105
|
+
const member = await session.bot.getGuildMember(guildId, userId);
|
|
106
|
+
if (member.nick && member.nick !== userId) return member.nick;
|
|
107
|
+
if (member.nickname && member.nickname !== userId) return member.nickname;
|
|
108
|
+
} catch (e) {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (userId) {
|
|
112
|
+
try {
|
|
113
|
+
const user = await session.bot.getUser(userId, guildId);
|
|
114
|
+
if (user.nick && user.nick !== userId) return user.nick;
|
|
115
|
+
if (user.name && user.name !== userId) return user.name;
|
|
116
|
+
if (user.username && user.username !== userId) return user.username;
|
|
117
|
+
} catch (e) {
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return quote.member?.nick || quote.member?.name || quote.author?.nickname || quote.author?.username || userId || "用户";
|
|
121
|
+
}, "getDisplayName");
|
|
95
122
|
const getImageBuffer = /* @__PURE__ */ __name(async (session) => {
|
|
96
123
|
let targetImgUrl = null;
|
|
97
124
|
const currImg = session.elements.find((e) => e.type === "img" || e.type === "image");
|
|
98
|
-
if (currImg)
|
|
99
|
-
targetImgUrl = currImg.attrs.src || currImg.attrs.url;
|
|
100
|
-
}
|
|
125
|
+
if (currImg) targetImgUrl = currImg.attrs.src || currImg.attrs.url;
|
|
101
126
|
if (!targetImgUrl && session.quote) {
|
|
102
|
-
const
|
|
103
|
-
const quoteImg =
|
|
127
|
+
const quote = session.quote;
|
|
128
|
+
const quoteImg = quote.elements.find((e) => e.type === "img" || e.type === "image");
|
|
104
129
|
if (quoteImg) {
|
|
105
130
|
targetImgUrl = quoteImg.attrs.src || quoteImg.attrs.url;
|
|
106
131
|
} else {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
132
|
+
const userId = quote.user?.id || quote.author?.id;
|
|
133
|
+
let avatarUrl = "https://koishi.chat/logo.png";
|
|
134
|
+
if (userId && /^\d+$/.test(userId)) {
|
|
135
|
+
avatarUrl = `https://q1.qlogo.cn/g?b=qq&nk=${userId}&s=640`;
|
|
136
|
+
} else if (quote.author?.avatar) {
|
|
137
|
+
avatarUrl = quote.author.avatar;
|
|
138
|
+
}
|
|
139
|
+
const username = await getDisplayName(session, quote);
|
|
140
|
+
const textContent = quote.content || " ";
|
|
111
141
|
const html = generateQuoteHtml(avatarUrl, username, textContent);
|
|
112
142
|
try {
|
|
113
143
|
const page = await ctx.puppeteer.page();
|
|
114
144
|
await page.setContent(html);
|
|
145
|
+
await (0, import_koishi.sleep)(200);
|
|
115
146
|
const element = await page.$(".container");
|
|
116
147
|
const buffer = await element?.screenshot({ type: "png" });
|
|
117
148
|
await page.close();
|
|
118
149
|
return { buffer, ext: ".png" };
|
|
119
150
|
} catch (e) {
|
|
120
|
-
ctx.logger.error("Puppeteer
|
|
151
|
+
ctx.logger.error("Puppeteer 截图失败", e);
|
|
121
152
|
return { buffer: null, ext: "" };
|
|
122
153
|
}
|
|
123
154
|
}
|
|
@@ -131,7 +162,6 @@ function apply(ctx, config) {
|
|
|
131
162
|
else if (targetImgUrl.includes(".webp")) ext = ".webp";
|
|
132
163
|
return { buffer: Buffer.from(buffer), ext };
|
|
133
164
|
} catch (e) {
|
|
134
|
-
ctx.logger.error("下载图片失败", e);
|
|
135
165
|
return { buffer: null, ext: "" };
|
|
136
166
|
}
|
|
137
167
|
}
|
|
@@ -144,12 +174,10 @@ function apply(ctx, config) {
|
|
|
144
174
|
} catch (e) {
|
|
145
175
|
}
|
|
146
176
|
}, "withdrawLater");
|
|
147
|
-
ctx.command("上传 <folderName>"
|
|
177
|
+
ctx.command("上传 <folderName>").action(async ({ session }, folderName) => {
|
|
148
178
|
if (!folderName) return "请输入文件夹名称。";
|
|
149
179
|
const { buffer, ext } = await getImageBuffer(session);
|
|
150
|
-
if (!buffer)
|
|
151
|
-
return "无法获取图片。请直接附带图片,或引用含有图片/文字的消息。";
|
|
152
|
-
}
|
|
180
|
+
if (!buffer) return "无法获取图片。请附带图片或引用消息。";
|
|
153
181
|
const targetDir = path.join(root, folderName);
|
|
154
182
|
let shouldUpload = false;
|
|
155
183
|
if (!fs.existsSync(targetDir)) {
|
|
@@ -189,21 +217,37 @@ function apply(ctx, config) {
|
|
|
189
217
|
}
|
|
190
218
|
} catch (error) {
|
|
191
219
|
ctx.logger.error(error);
|
|
192
|
-
return "
|
|
220
|
+
return "保存失败。";
|
|
193
221
|
}
|
|
194
222
|
}
|
|
195
223
|
});
|
|
196
224
|
ctx.middleware(async (session, next) => {
|
|
197
225
|
const content = session.content.trim();
|
|
198
226
|
if (!content) return next();
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
227
|
+
let foldersToSearch = [content];
|
|
228
|
+
for (const group of config.associations) {
|
|
229
|
+
if (group.includes(content)) {
|
|
230
|
+
foldersToSearch = group;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
let allImages = [];
|
|
235
|
+
for (const folder of foldersToSearch) {
|
|
236
|
+
const dirPath = path.join(root, folder);
|
|
237
|
+
if (dirPath.startsWith(root) && fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
238
|
+
const files = fs.readdirSync(dirPath).filter((file) => /\.(jpg|jpeg|png|gif|webp)$/i.test(file));
|
|
239
|
+
files.forEach((f) => {
|
|
240
|
+
allImages.push({
|
|
241
|
+
path: path.join(dirPath, f),
|
|
242
|
+
folder
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (allImages.length > 0) {
|
|
248
|
+
const randomImg = allImages[Math.floor(Math.random() * allImages.length)];
|
|
249
|
+
await session.send(import_koishi.h.image("file://" + randomImg.path));
|
|
250
|
+
return;
|
|
207
251
|
}
|
|
208
252
|
return next();
|
|
209
253
|
});
|