kokkoro-plugin-setu
Version:
265 lines (264 loc) • 9.75 kB
JavaScript
;
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;