diff --git a/src/server/queue/download.ts b/src/server/queue/download.ts index eea4a8d..b14340f 100644 --- a/src/server/queue/download.ts +++ b/src/server/queue/download.ts @@ -3,7 +3,7 @@ import { Job, Queue, Worker } from 'bullmq'; import { sanitizer } from '../../utils'; import { logger } from '../../utils/logging'; import { prisma } from '../db/client'; -import { downloadChapter, getChapterFromLocal } from '../utils/mangal'; +import { downloadChapter, getChapter, getChapterFromLocal } from '../utils/mangal'; import { integrationQueue } from './integration'; import { notificationQueue } from './notify'; @@ -17,6 +17,13 @@ export interface IDownloadWorkerData { chapterIndex: number; } +interface Download { + index: number; + size: number; + createdAt: Date; + fileName: string; +} + export const downloadWorker = new Worker( 'downloadQueue', async (job: Job) => { @@ -36,8 +43,27 @@ export const downloadWorker = new Worker( }); return; } - filePath = await downloadChapter(mangaInDb.title, mangaInDb.source, chapterIndex, mangaInDb.library.path); - const chapter = await getChapterFromLocal(filePath); + const download = async (index: number, up: boolean): Promise => { + const chapter = await getChapter(mangaInDb.title, mangaInDb.source, index, mangaInDb.library.path); + if (chapter.index === chapterIndex) { + filePath = await downloadChapter(mangaInDb.title, mangaInDb.source, index, mangaInDb.library.path); + + return getChapterFromLocal(filePath); + } + if (up) { + return download(index + 1, true); + } + if (index === 0) { + throw new Error(`Not found chapter ${chapterIndex}`); + } + return download(index - 1, false); + }; + let chapter; + try { + chapter = await download(chapterIndex, true); + } catch (error) { + chapter = await download(chapterIndex, false); + } await prisma.chapter.deleteMany({ where: { diff --git a/src/server/utils/mangal.ts b/src/server/utils/mangal.ts index 38e1bce..ef514cf 100644 --- a/src/server/utils/mangal.ts +++ b/src/server/utils/mangal.ts @@ -302,6 +302,52 @@ export const downloadChapter = async ( } }; +export interface ChapterMangal { + name: string; + url: string; + index: number; + id: number; + volume: number; + pages: null | number; +} +export const getChapter = async ( + title: string, + source: string, + chapterIndex: number, + libraryPath: string, +): Promise => { + try { + logger.info(`Get chapter #${chapterIndex} for ${title} from ${source}`); + const { stdout, stderr, escapedCommand } = await execa( + 'mangal', + ['inline', '--source', source, '--query', title, '--manga', 'exact', '--chapters', `${chapterIndex}`, '-j'], + { + cwd: libraryPath, + }, + ); + + logger.info(`Get chapter with following command: ${escapedCommand}`); + + if (stderr) { + logger.error(`Failed to get the chapter #${chapterIndex} for ${title}. Err:\n${stderr}`); + throw new Error(stderr); + } else { + logger.info(`Get chapter #${chapterIndex} for ${title}. Result:\n${stdout}`); + } + const response = JSON.parse(stdout.trim()); + if (Array.isArray(response?.result) && response?.result.length > 0) { + const chapters = response?.result[0].mangal.chapters; + if (Array.isArray(chapters) && chapters.length > 0) { + return response?.result[0].mangal.chapters[0]; + } + } + throw new Error('Failed to Get the chapter'); + } catch (err) { + logger.error(`Failed to Get the chapter #${chapterIndex} for ${title}. Err:\n${err}`); + throw err; + } +}; + export const getChapterIndexFromFile = (chapterFile: string) => { const indexRegexp = /.*?\[(\d+)\].*/; const match = indexRegexp.exec(path.basename(chapterFile));