@tomisakae/syosetu-api
Version:
Enterprise-grade Fastify TypeScript API for Syosetu.com data extraction using official API and web scraping. Run instantly with 'npx @tomisakae/syosetu-api'
204 lines • 9.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.syosetuController = exports.SyosetuController = void 0;
const utils_1 = require("@/utils");
const services_1 = require("@/services");
const logger = (0, utils_1.createChildLogger)('SyosetuController');
class SyosetuController {
async getNovelDetails(request, reply) {
try {
const { ncode } = request.params;
if (!(0, utils_1.validateNcode)(ncode)) {
(0, utils_1.sendError)(reply, 'Ncode không hợp lệ (chỉ chấp nhận chữ và số)', 400);
return;
}
logger.info(`Getting novel details for ncode: ${ncode}`);
const result = await services_1.syosetuService.getNovelMetadata(ncode);
if (result.success) {
(0, utils_1.sendSuccess)(reply, result.data, 'Lấy thông tin tiểu thuyết thành công');
}
else {
(0, utils_1.sendNotFound)(reply, 'Tiểu thuyết');
}
}
catch (error) {
logger.error('Error in getNovelDetails:', error);
(0, utils_1.sendInternalError)(reply, 'Lỗi server khi lấy thông tin tiểu thuyết');
}
}
async getChapterContent(request, reply) {
try {
const { ncode, chapter } = request.params;
if (!(0, utils_1.validateNcode)(ncode)) {
(0, utils_1.sendError)(reply, 'Ncode không hợp lệ', 400);
return;
}
const chapterNumber = (0, utils_1.validateChapterNumber)(chapter);
if (chapterNumber === null) {
(0, utils_1.sendError)(reply, 'Chapter phải là số nguyên dương', 400);
return;
}
logger.info(`Getting chapter content for ncode: ${ncode}, chapter: ${chapterNumber}`);
const result = await services_1.syosetuService.getChapterContent(ncode, chapterNumber);
if (result.success) {
(0, utils_1.sendSuccess)(reply, result.data, 'Lấy nội dung chapter thành công');
}
else {
(0, utils_1.sendNotFound)(reply, 'Chapter');
}
}
catch (error) {
logger.error('Error in getChapterContent:', error);
(0, utils_1.sendInternalError)(reply, 'Lỗi server khi lấy nội dung chapter');
}
}
async getMultipleChapters(request, reply) {
try {
const { ncode } = request.params;
const { chapters } = request.body;
if (!(0, utils_1.validateNcode)(ncode)) {
(0, utils_1.sendError)(reply, 'Ncode không hợp lệ', 400);
return;
}
if (!chapters || !Array.isArray(chapters) || chapters.length === 0) {
(0, utils_1.sendError)(reply, 'Chapters phải là array không rỗng', 400);
return;
}
if (chapters.length > 10) {
(0, utils_1.sendError)(reply, 'Tối đa 10 chapters mỗi lần', 400);
return;
}
for (const chapter of chapters) {
if (typeof chapter !== 'number' || chapter < 1) {
(0, utils_1.sendError)(reply, `Chapter ${chapter} không hợp lệ`, 400);
return;
}
}
logger.info(`Getting multiple chapters for ncode: ${ncode}, chapters: ${chapters.join(', ')}`);
const results = await Promise.all(chapters.map(chapter => services_1.syosetuService.getChapterContent(ncode, chapter)));
const successfulResults = results.filter(result => result.success);
const failedResults = results.filter(result => !result.success);
(0, utils_1.sendSuccess)(reply, {
ncode,
totalRequested: chapters.length,
successful: successfulResults.length,
failed: failedResults.length,
chapters: successfulResults.map(result => result.data),
errors: failedResults.map(result => result.error),
}, 'Lấy nhiều chapter hoàn tất');
}
catch (error) {
logger.error('Error in getMultipleChapters:', error);
(0, utils_1.sendInternalError)(reply, 'Lỗi server khi lấy nhiều chapter');
}
}
async searchNovels(request, reply) {
try {
const { keyword, order = 'new', limit = '20', start, gzip, ...otherOptions } = request.query;
if (!keyword) {
(0, utils_1.sendError)(reply, 'Keyword là bắt buộc', 400);
return;
}
if (!(0, utils_1.validateSearchOrder)(order)) {
(0, utils_1.sendError)(reply, 'Order không hợp lệ', 400, {
validOrders: {
new: 'Mới nhất',
favnovelcnt: 'Bookmark nhiều nhất',
reviewcnt: 'Review nhiều nhất',
hyoka: 'Điểm cao nhất',
weeklypoint: 'Điểm tuần',
monthlypoint: 'Điểm tháng',
yearlypoint: 'Điểm năm',
weekly: 'Weekly unique users',
},
});
return;
}
const limitNum = parseInt(limit, 10);
if (!(0, utils_1.validateLimit)(limitNum, 500)) {
(0, utils_1.sendError)(reply, 'Limit phải từ 1 đến 500', 400);
return;
}
if (start) {
const startNum = parseInt(start, 10);
if (!(0, utils_1.validateStartPosition)(startNum)) {
(0, utils_1.sendError)(reply, 'Start position phải từ 1 đến 2000', 400);
return;
}
}
if (gzip) {
const gzipNum = parseInt(gzip, 10);
if (!(0, utils_1.validateGzipLevel)(gzipNum)) {
(0, utils_1.sendError)(reply, 'Gzip level phải từ 1 đến 5', 400);
return;
}
}
const options = {
order,
limit: limitNum,
...(start && { start: parseInt(start, 10) }),
...(gzip && { gzip: parseInt(gzip, 10) }),
...Object.fromEntries(Object.entries(otherOptions).map(([key, value]) => [
key,
typeof value === 'string' && /^\d+$/.test(value)
? parseInt(value, 10)
: value,
])),
};
logger.info(`Searching novels with keyword: ${keyword}`);
const result = await services_1.syosetuService.searchNovels(keyword, options);
if (result.success) {
(0, utils_1.sendSuccess)(reply, result.data, 'Tìm kiếm thành công');
}
else {
(0, utils_1.sendError)(reply, result.error || 'Lỗi khi tìm kiếm', 500);
}
}
catch (error) {
logger.error('Error in searchNovels:', error);
(0, utils_1.sendInternalError)(reply, 'Lỗi server khi tìm kiếm tiểu thuyết');
}
}
async getRanking(request, reply) {
try {
const { order = 'hyoka', biggenre, genre, limit = '50' } = request.query;
if (!(0, utils_1.validateRankingOrder)(order)) {
(0, utils_1.sendError)(reply, 'Order không hợp lệ cho ranking', 400, {
validOrders: {
hyoka: 'Điểm đánh giá cao nhất',
favnovelcnt: 'Bookmark nhiều nhất',
weeklypoint: 'Điểm tuần cao nhất',
monthlypoint: 'Điểm tháng cao nhất',
},
});
return;
}
const limitNum = parseInt(limit, 10);
if (!(0, utils_1.validateLimit)(limitNum, 100)) {
(0, utils_1.sendError)(reply, 'Limit phải từ 1 đến 100', 400);
return;
}
const options = {
order,
limit: limitNum,
...(biggenre && { biggenre }),
...(genre && { genre }),
};
logger.info('Getting ranking');
const result = await services_1.syosetuService.getRanking(options);
if (result.success) {
(0, utils_1.sendSuccess)(reply, result.data, 'Lấy ranking thành công');
}
else {
(0, utils_1.sendError)(reply, result.error || 'Lỗi khi lấy ranking', 500);
}
}
catch (error) {
logger.error('Error in getRanking:', error);
(0, utils_1.sendInternalError)(reply, 'Lỗi server khi lấy ranking');
}
}
}
exports.SyosetuController = SyosetuController;
exports.syosetuController = new SyosetuController();
//# sourceMappingURL=syosetu.controller.js.map