koishi-plugin-adapter-iirose
Version:
[IIROSE-蔷薇花园](https://iirose.com/)适配器
113 lines (97 loc) • 4.27 kB
text/typescript
import { h } from 'koishi';
import { IIROSE_Bot } from '../bot/bot';
export async function clearMsg(msg: string, bot: IIROSE_Bot)
{
// 处理 markdown 元素:移除开头的 `\\\\\\*\n` 前缀
// 处理 markdown 元素:移除开头的 `\\\*\n` (即 \\\*\n) 前缀
// IIROSE 发送的原始消息中,反斜杠被编码为 HTML 实体
msg = msg.replace(/^(?:\){3}\*\n\s*/, '');
// 处理 a 元素:移除开头的反斜杠
msg = msg.replace(/\\(https*:\/\/[\s\S]+)/g, '$1');
// 优先处理历史遗留的图片格式 `[url#e]`,将其转换为裸链接
msg = msg.replace(/\[((https*:\/\/[\s\S]+?\.(png|jpg|jpeg|gif))(#e)*)\]/g, '$1');
async function replaceAsync(str: string, regex: RegExp, asyncFn: (...args: any[]) => Promise<string>)
{
const promises: Promise<string>[] = [];
str.replace(regex, (...args) =>
{
promises.push(asyncFn(...args));
return '';
});
const data = await Promise.all(promises);
return str.replace(regex, () => data.shift()!);
}
// 处理图片 (同步)
const imageUrlRegex = /((?:https?:\/\/[\s\S]+?)\.(?:png|jpg|jpeg|gif)(?:#e)?)/g;
msg = msg.replace(imageUrlRegex, (match) =>
{
const cleanUrl = match.replace(/#e$/, '');
return h.image(cleanUrl).toString();
});
// 处理音频 (同步)
const audioUrlRegex = /((?:https?:\/\/[\s\S]+?)\.weba)/g;
msg = msg.replace(audioUrlRegex, (match) =>
{
// 将 .weba 结尾的链接转换为 audio 元素
return h.audio(match).toString();
});
// 处理视频 (同步)
const videoUrlRegex = /\[((?:https?:\/\/[\s\S]+?)\.(?:mp4|webm|ogg))\]/g;
msg = msg.replace(videoUrlRegex, (match, url) =>
{
// 将 [url.mp4] 格式转换为 video 元素
return h.video(url).toString();
});
// 处理 at-by-name (异步)
// 消耗前后空格,但将空格捕获以便在替换时放回
// 匹配一个或多个前导空格,以便在消息开头正确处理 at
const atNameRegex = /(\s+)((?:\[\*[\s\S]+?\*\])+)(\s)/g;
msg = await replaceAsync(msg, atNameRegex, async (raw, space1, mentionBlock, space2, offset, originalString) =>
{
const name = mentionBlock.slice(2, -2);
const isMultiBlock = mentionBlock.lastIndexOf('[*') > 0;
const user = await bot.internal.getUserByName(name);
// 如果 at 元素位于消息开头(或只由空格开头),则不保留前面的空格
const leadingSpace = (offset === 0 || originalString.substring(0, offset).trim() === '') ? '' : space1;
if (user)
{
return `${leadingSpace}${h('at', { id: user.id, name }).toString()}${space2}`;
}
else if (isMultiBlock)
{
return `${leadingSpace}${h('at', { id: 'error', name }).toString()}${space2}`;
}
return raw;
});
// 处理 at-by-id (异步)
const atIdRegex = /(\s+)((?:\[@[\s\S]+?@\])+)(\s)/g;
msg = await replaceAsync(msg, atIdRegex, async (raw, space1, mentionBlock, space2, offset, originalString) =>
{
const id = mentionBlock.slice(2, -2);
const isMultiBlock = mentionBlock.lastIndexOf('[@') > 0;
const user = await bot.getUser(id);
// 如果 at 元素位于消息开头(或只由空格开头),则不保留前面的空格
const leadingSpace = (offset === 0 || originalString.substring(0, offset).trim() === '') ? '' : space1;
if (user)
{
return `${leadingSpace}${h('at', { id, name: user.name }).toString()}${space2}`;
}
else if (isMultiBlock)
{
return `${leadingSpace}${h('at', { id: 'error', name: id }).toString()}${space2}`;
}
return raw;
});
// 处理 sharp 元素(提及频道)
const sharpRegex = /(\s+)((?:\[_[\s\S]+?_\])+)(\s)/g;
msg = await replaceAsync(msg, sharpRegex, async (raw, space1, mentionBlock, space2, offset, originalString) =>
{
// 如果 sharp 元素位于消息开头(或只由空格开头),则不保留前面的空格
const leadingSpace = (offset === 0 || originalString.substring(0, offset).trim() === '') ? '' : space1;
const channelId = mentionBlock.slice(2, -2);
// 移除频道ID末尾的下划线
const cleanChannelId = channelId.replace(/_+$/, '');
return `${leadingSpace}${h('sharp', { id: cleanChannelId }).toString()}${space2}`;
});
return msg;
}