koishi-plugin-jmcomic-api
Version:
187 lines (186 loc) • 7.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.logger = exports.usage = exports.inject = exports.Config = exports.name = void 0;
exports.apply = apply;
const koishi_1 = require("koishi");
exports.name = 'jmcomic-api';
exports.Config = koishi_1.Schema.intersect([
koishi_1.Schema.object({
apiUrl: koishi_1.Schema.string().description('API 地址(注意末尾不要带 / )').required(),
defaultPassword: koishi_1.Schema.string().description('默认加密密码').default(''),
}).description('基础设置'),
koishi_1.Schema.object({
getDataMethod: koishi_1.Schema.union([
koishi_1.Schema.const('base64').description('base64'),
koishi_1.Schema.const('form-data').description('form-data'),
koishi_1.Schema.const('url').description('url'),
]).default('url').description('获取文件的方式'),
}).description('进阶设置'),
]);
exports.inject = {
required: ['http'],
optional: ['jmcomic'],
};
exports.usage = `
# 安装 <br>
1.后端安装前需要Python <br>
2.在终端执行以下指令 <br>
\`\`\`
pip install jmcomic_api
python -m jmcomic_api
\`\`\` <br>
把API填入配置即可 <br>
`;
function apply(ctx, config) {
exports.logger = new koishi_1.Logger(exports.name);
ctx.on('ready', async () => {
exports.logger.info('JMComic API 服务初始化中...');
ctx.plugin(JMComicService, config);
exports.logger.info('JMComic API 服务已启动');
setupCommands(ctx, config);
});
ctx.on('dispose', () => {
exports.logger.info('JMComic API 服务已卸载');
});
}
class JMComicService extends koishi_1.Service {
config;
constructor(ctx, config) {
super(ctx, 'jmcomic', true);
this.config = config;
}
async fetchAPI(endpoint) {
try {
const response = await this.ctx.http.get(`${this.config.apiUrl}${endpoint}`);
return response.data;
}
catch (error) {
if (koishi_1.HTTP.Error.is(error)) {
const response = error.response;
if (response?.status === 400) {
const data = response.data?.data || {};
throw new Error(data.log || 'API 请求错误');
}
}
throw error;
}
}
async getRanking(type = 'day', page = 1) {
const data = await this.fetchAPI(`/get/raw/ranking?page=${page}&types=${type}`);
return data.raw_results[type].content;
}
async search(keyword, type = 'site', page = 1) {
const data = await this.fetchAPI(`/get/raw/search?page=${page}&text=${encodeURIComponent(keyword)}&types=${type}`);
return data.raw_results[type].content;
}
async getComicInfo(jm_id) {
const data = await this.fetchAPI(`/get/raw?jm_id=${jm_id}&types=info`);
return data.raw_info;
}
async prepareDownload(jm_id, noCache = false) {
await this.fetchAPI(`/download/image?jm_id=${jm_id}&no_cache=${noCache}`);
}
async getFileData(jm_id, fileType, password) {
const url = `/get/file?jm_id=${jm_id}` +
`&file_type=${fileType}&return_method=${this.config.getDataMethod}` +
(password ? `&file_pwd=${password}` : '');
if (this.config.getDataMethod === 'form-data') {
return this.config.apiUrl + url;
}
const response = await this.fetchAPI(url);
return response.file;
}
}
function setupCommands(ctx, config) {
ctx.command('jm.ranking [type:string] [page:number]', '本子排名')
.alias('jm.排名')
.option('page', '-p <page:number> 页数', { fallback: 1 })
.option('type', '-t <type:string> 排名类型', {
type: ['day', 'week', 'month'],
fallback: 'day',
})
.action(async ({ options }, type, page) => {
type = type || options.type;
const results = await ctx.jmcomic.getRanking(type, page || options.page);
return formatResults('ranking', type || options.type, results);
});
ctx.command('jm.search <keyword:string>', '搜索本子')
.alias('jm.搜索')
.option('page', '-p <page:number> 页数', { fallback: 1 })
.option('type', '-t <type:string> 搜索类型', {
type: ['site', 'author', 'tags', 'work'],
fallback: 'site'
})
.action(async ({ options }, keyword) => {
if (!keyword)
return '请输入搜索关键词';
const results = await ctx.jmcomic.search(keyword, options.type, options.page);
return formatResults('search', options.type, results);
});
ctx.command('jm.info <jm_id:number>', '获取本子信息')
.alias('jm.信息')
.action(async (_, jm_id) => {
if (!jm_id)
return '请输入有效本子ID';
const info = await ctx.jmcomic.getComicInfo(jm_id);
return formatComicInfo(jm_id, info);
});
ctx.command('jm.get <jm_id:number>', '获取本子文件')
.alias('jm.获取')
.option('type', '-t <type:string> 文件类型', {
type: ['pdf', 'zip'],
fallback: 'pdf'
})
.option('password', '-p <password:string> 解压密码')
.option('noCache', '-c 禁用缓存')
.action(async ({ options }, jm_id) => {
try {
await ctx.jmcomic.prepareDownload(jm_id, options.noCache);
const data = await ctx.jmcomic.getFileData(jm_id, options.type, options.password || config.defaultPassword);
switch (ctx.jmcomic.config.getDataMethod) {
case 'base64':
return koishi_1.h.file(Buffer.from(data, 'base64'), options.type, { title: `${jm_id}.${options.type}` });
case 'url':
return koishi_1.h.file(data, { title: `${jm_id}.${options.type}` });
case 'form-data':
return koishi_1.h.file(data, { title: `${jm_id}.${options.type}` });
default:
return '不支持的返回方式';
}
}
catch (error) {
return error.message;
}
});
}
function formatResults(type, subType, results) {
if (!results?.length)
return '未找到相关内容';
const titles = {
ranking: {
day: '📅 今日排行榜',
week: '📆 本周排行榜',
month: '🗓️ 本月排行榜'
},
search: {
site: '🔍 全站搜索结果',
tags: '🏷️ 标签搜索结果',
author: '👤 作者作品',
work: '📚 系列作品'
}
};
const header = titles[type][subType] + '\n\n';
return header + results.map(([id, details]) => `🚗 车牌号: ${id}
📖 名称: ${details.name}
🏷️ 标签: ${details.tags?.join(', ') || '无'}
━━━━━━━━━━━━━━━━━━━`).join('\n\n');
}
function formatComicInfo(jm_id, info) {
return `🚗 车牌号: ${jm_id}
📛 名称: ${info.idoname}
👤 作者: ${info.author}
💬 评论数: ${info.comment_count}
❤️ 点赞量: ${info.likes}
👀 浏览量: ${info.views}
🏷️ 标签: ${info.tags?.join(', ') || '无'}`;
}