UNPKG

kokkoro-plugin-setu

Version:
265 lines (264 loc) 9.75 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Service = exports.r18_path = exports.r17_path = void 0; const axios_1 = __importDefault(require("axios")); const path_1 = require("path"); const events_1 = require("events"); const fs_1 = require("fs"); const promises_1 = require("fs/promises"); const amesu_1 = require("amesu"); const utils_1 = require("@kokkoro/utils"); const images_path = (0, path_1.join)(__dirname, '../images'); exports.r17_path = (0, path_1.join)(__workname, `/data/setu/r17`); exports.r18_path = (0, path_1.join)(__workname, `/data/setu/r18`); class Service extends events_1.EventEmitter { plugin; /** API */ api; /** 代理 */ proxy; /** 本地最大缓存图片数 */ max_setu; /** 单次补充图片数 */ reload_num; /** 补充图片 cd */ reload_delay; /** 表情包 */ memes; lspMap; imageList; reload; constructor( /** 插件 */ plugin) { super(); this.plugin = plugin; this.api = 'https://api.lolicon.app/setu/v2'; this.proxy = process.env.SETU_PROXY ?? 'i.pixiv.re'; this.max_setu = Number(process.env.SETU_COUNT ?? 500); this.reload_num = 20; this.reload_delay = Number(process.env.SETU_DELAY ?? 300000); this.memes = []; this.lspMap = new Map(); this.imageList = { r17: [], r18: [] }; this.init(); this.reload = this.reloadSetu(); this.on('setu.send.success', (bot, url, file) => { (0, promises_1.unlink)(url) .then(() => { this.plugin.logger.mark(`图片发送成功,已删除 ${file}`); }) .catch((error) => { this.plugin.logger.error(error.message); }); }); } async init() { try { this.memes.push(...(await (0, promises_1.readdir)(images_path))); this.imageList.r17 = await (0, promises_1.readdir)(exports.r17_path); this.imageList.r18 = await (0, promises_1.readdir)(exports.r18_path); } catch (error) { !(0, fs_1.existsSync)((0, path_1.join)(__workname, `/data`)) && (await (0, promises_1.mkdir)((0, path_1.join)(__workname, `/data`))); await (0, promises_1.mkdir)((0, path_1.join)(__workname, `/data/setu`)); await (0, promises_1.mkdir)(exports.r17_path); await (0, promises_1.mkdir)(exports.r18_path); } this.reload(); } /** * 补充色图 */ reloadSetu() { return (0, utils_1.throttle)(async () => { for (let i = 0; i < 2; i++) { const type = !i ? 'r17' : 'r18'; const list_length = this.imageList[type].length; if (list_length > this.max_setu) { this.plugin.logger.mark(`${type} 库存充足,不用补充`); continue; } const param = { proxy: this.proxy, r18: i, num: this.reload_num, size: ['regular'], }; this.plugin.logger.mark(`${type} 色图正在补充中...`); try { const images = await this.getLoliconImages(param); const images_length = images.length; const taskQueue = []; for (let i = 0; i < images_length; i++) { const image = images[i]; // 在 windows 下文件名不能包含 \ / : * ? " < > | const regex = /(\\|\/|:|\*|\?|"|<|>|\|)/g; let { urls, uid, author, pid, title } = image; let { regular: url } = urls; // 若出现非法字符则替换为 ⃺ title = title.replace(regex, '⃺'); author = author.replace(regex, '⃺'); const setu_path = type === 'r17' ? exports.r17_path : exports.r18_path; // pid 与 title 之间使用 @ 符分割 const setu_name = `${uid}@${author}@${pid}@${title}`; const setu_url = (0, path_1.join)(setu_path, setu_name); taskQueue.push(axios_1.default .get(url, { responseType: 'arraybuffer' }) .then((response) => (0, promises_1.writeFile)(setu_url, response.data, 'binary')) .then(() => { this.imageList[type].push(setu_name); this.plugin.logger.debug(`setu write success, ${pid} ${title}`); }) .catch((error) => { this.plugin.logger.error(`setu write error, ${error.message}`); })); } await Promise.allSettled(taskQueue); this.plugin.logger.mark(`${type} 色图补充完毕`); } catch (error) { this.plugin.logger.error(`获取 ${type} 色图失败,${error.message}`); } } }, this.reload_delay); } /** * 小黑屋 * * @param ctx - 消息上下文 * @returns 是否将 lsp 关进小黑屋 */ smallBlackRoom(ctx) { const { bot, group_id, sender, option } = ctx; const { user_id } = sender; const { max_lsp } = option; // 判断 lsp 要了几张图,超过 max_lsp 张关小黑屋 !this.lspMap.has(user_id) && this.lspMap.set(user_id, 0); if (this.lspMap.get(user_id) >= max_lsp) { const meme = this.getNotEroMeme(); const image = amesu_1.segment.image(meme); ctx.reply(image, true); bot.setGroupBan(group_id, user_id, 60 * 5); return true; } else { return false; } } clearLspMap() { this.lspMap.clear(); } /** * 获取涩图 * * @param param Lolicon 参数 * @returns */ async getLoliconImages(param) { try { const { data } = await axios_1.default.post(this.api, param); const { error } = data; if (error) { this.plugin.logger.error(error); throw new Error(error); } return data.data; } catch (error) { throw error; } } /** 获取不可以色色表情包 */ getNotEroMeme() { const index = Math.floor(Math.random() * this.memes.length); const meme = (0, path_1.join)(images_path, this.memes[index]); return meme; } /** * 获取随机涩图 * * @param r18 - 是否 r18 * @returns 色图信息 */ getRandomSetu(r18) { this.reload(); const setus = this.getSetus(r18); const setus_length = setus.length; if (!setus_length) { throw new Error('色图库存不足,请等待自动补充'); } const setu_file = setus.pop(); const setu_url = (0, path_1.join)(r18 ? exports.r18_path : exports.r17_path, setu_file); const [uid, author, pid, title] = setu_file.split('@'); const image_info = `作者:\n ${author} (${uid})\n标题:\n ${title} (${pid})`; return { image_info, setu_url, setu_file, }; } /** * 获取在线涩图 * * @param tags - 图片 tag * @param option - 群插件配置 * @returns */ async searchLoliconImage(tags, option) { const { r18, flash, size } = option; const param = { proxy: this.proxy, r18: +r18, size: [size], tag: [tags], }; try { const images = await this.getLoliconImages(param); const images_length = images.length; if (images_length) { const { pid, uid, title, author, tags, urls } = images[0]; const setu_url = urls[size]; const image_info = `作者:\n ${author} (${uid})\n标题:\n ${title} (${pid})\n标签:\n ${tags .map((tag) => `[${tag}]`) .join(' ')}`; return { image_info, setu_url, flash }; } else { throw new Error(`不存在 ${tags} 标签`); } } catch (error) { throw error; } } /** * 消息撤回 * * @param bot - bot 实例 * @param info - 撤回信息 */ unsendSetu(bot, info) { const { unsend, message_id, user_id } = info; if (unsend > 0) { // 撤回色图 setTimeout(() => { bot.deleteMsg(message_id); }, unsend * 1000); } this.lspMap.set(user_id, this.lspMap.get(user_id) + 1); } /** * 获取本地涩图列表 * * @param r18 - 是否获取 r18 * @returns 图片字符串数组 */ getSetus(r18) { return this.imageList[r18 ? 'r18' : 'r17']; } } exports.Service = Service;