mangakonekuto
Version:
Your CLI for reading manga from the terminal
224 lines (223 loc) ⢠10.2 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const inquirer_1 = __importDefault(require("inquirer"));
const ora_1 = __importDefault(require("ora"));
const open_1 = __importDefault(require("open"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const SettingsConfig_1 = __importDefault(require("../SettingsConfig"));
// modular loaders
const Loader_1 = __importDefault(require("../../modules/mangakakalot/Loader"));
class MangaEventHandler {
constructor() {
this.lastDownloadedFolder = null;
this.currentServer = null;
}
parseChapterNumber(title) {
const match = title.match(/chapter\s*(\d+(\.\d+)?)/i);
if (match && match[1])
return parseFloat(match[1]);
return Number.MAX_SAFE_INTEGER;
}
cleanupPreviousDownload() {
return __awaiter(this, void 0, void 0, function* () {
const shouldDelete = SettingsConfig_1.default.get("Settings.DeletePrevious") || false;
if (shouldDelete && this.lastDownloadedFolder) {
try {
yield fs_extra_1.default.remove(this.lastDownloadedFolder);
}
catch (_a) {
// ignore
}
}
});
}
setupServer() {
const enabledServers = SettingsConfig_1.default.get("Settings.Server") || [];
if (enabledServers.includes("MangaKakalot")) {
this.currentServer = Loader_1.default;
return true;
}
// future:
// if (enabledServers.includes("MangaDex")) {
// this.currentServer = MangaDex;
// return true;
// }
console.log('\nā ļø No supported servers enabled in your settings.');
console.log('Please enable a server in Settings -> Enable Server.');
return false;
}
manage() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!this.setupServer())
return;
console.log(`\nš Using ${(_a = this.currentServer) === null || _a === void 0 ? void 0 : _a.name} as your manga source.`);
const searchAnswer = yield inquirer_1.default.prompt([
{
type: 'input',
name: 'query',
message: 'Enter the manga title to search for:',
},
]);
const searchSpinner = (0, ora_1.default)('Searching...').start();
const searchResults = yield this.currentServer.searchManga(searchAnswer.query);
searchSpinner.stop();
if (searchResults.length === 0) {
console.log('No results found.');
return;
}
const mangaChoices = searchResults.map((manga) => ({
name: `${manga.title} - Author: ${manga.author}`,
value: manga,
}));
const selectAnswer = yield inquirer_1.default.prompt([
{
type: 'rawlist',
name: 'selectedManga',
message: 'Select a manga:',
choices: mangaChoices,
},
]);
const selectedManga = selectAnswer.selectedManga;
const infoSpinner = (0, ora_1.default)('Loading manga info...').start();
const mangaInfo = yield this.currentServer.getMangaDetail(selectedManga.id);
infoSpinner.stop();
if (!mangaInfo) {
console.log('Failed to load manga details.');
return;
}
console.log(`\n=== Manga Information ===`);
console.log(`Title: ${mangaInfo.title}`);
console.log(`Image URL: ${mangaInfo.imageUrl}`);
console.log(`Summary:\n${mangaInfo.summary}\n`);
const actionAnswer = yield inquirer_1.default.prompt([
{
type: 'list',
name: 'action',
message: `What would you like to do?`,
choices: [
{ name: 'Select Chapter To Read', value: 'read' },
{ name: 'Back to Search', value: 'back' },
],
},
]);
if (actionAnswer.action === 'read') {
yield this.readChapters(selectedManga.id, mangaInfo.title);
}
else {
yield this.manage();
}
});
}
readChapters(mangaId, mangaTitle) {
return __awaiter(this, void 0, void 0, function* () {
const chapterSpinner = (0, ora_1.default)(`Loading chapters for "${mangaTitle}"...`).start();
let chapters = yield this.currentServer.getChapterList(mangaId);
chapterSpinner.stop();
if (chapters.length === 0) {
console.log('No chapters found.');
return;
}
chapters.sort((a, b) => this.parseChapterNumber(a.title) - this.parseChapterNumber(b.title));
let currentIndex;
while (true) {
if (typeof currentIndex !== 'number') {
const chapterChoices = chapters.map((ch, idx) => ({
name: `${ch.title} (${ch.date})`,
value: idx,
}));
const chapterAnswer = yield inquirer_1.default.prompt([
{
type: 'list',
name: 'chapterIndex',
message: `Select a chapter to read:`,
choices: chapterChoices,
},
]);
currentIndex = chapterAnswer.chapterIndex;
}
if (typeof currentIndex === 'number' && currentIndex < chapters.length) {
const selectedChapter = chapters[currentIndex];
console.log(`\nš Now reading: ${selectedChapter.title} (${selectedChapter.date}) [${currentIndex + 1} / ${chapters.length}]`);
const safeMangaTitle = mangaTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase();
const safeChapterTitle = selectedChapter.title.replace(/[^a-z0-9]/gi, '_').toLowerCase();
yield this.cleanupPreviousDownload();
const pdfPath = yield this.currentServer.getImagesAndCreatePDF(selectedChapter.url, safeMangaTitle, safeChapterTitle);
this.lastDownloadedFolder = path_1.default.dirname(pdfPath);
yield (0, open_1.default)(pdfPath);
const nextAction = yield inquirer_1.default.prompt([
{
type: 'list',
name: 'action',
message: `What do you want to do now?`,
choices: [
{ name: 'Read Next Chapter', value: 'next' },
{ name: 'Back to Chapter List', value: 'back' },
{ name: 'Back to Manga Search', value: 'search' },
],
},
]);
if (nextAction.action === 'next') {
currentIndex++;
if (currentIndex >= chapters.length) {
console.log('\nš No more chapters available.');
const backAnswer = yield inquirer_1.default.prompt([
{
type: 'confirm',
name: 'goBack',
message: 'Would you like to go back to the chapter list?',
default: true,
},
]);
if (backAnswer.goBack) {
currentIndex = undefined;
continue;
}
else {
break;
}
}
}
else if (nextAction.action === 'back') {
currentIndex = undefined;
}
else {
break;
}
}
else {
console.log('\nš No more chapters available.');
const backAnswer = yield inquirer_1.default.prompt([
{
type: 'confirm',
name: 'goBack',
message: 'Would you like to go back to the chapter list?',
default: true,
},
]);
if (backAnswer.goBack) {
currentIndex = undefined;
continue;
}
else {
break;
}
}
}
});
}
}
exports.default = MangaEventHandler;