diff --git a/plugins/english/leafstudio.ts b/plugins/english/leafstudio.ts new file mode 100644 index 0000000..976cbdf --- /dev/null +++ b/plugins/english/leafstudio.ts @@ -0,0 +1,125 @@ +import { CheerioAPI, load as parseHTML } from 'cheerio'; +import { Plugin } from '@/types/plugin'; +import { defaultCover } from '@libs/defaultCover'; +import { fetchApi } from '@libs/fetch'; +import { Filters } from '@libs/filterInputs'; + +class LeafStudio implements Plugin.PluginBase { + id = 'LeafStudio'; + name = 'LeafStudio'; + icon = 'src/en/leafstudio/icon.png'; + site = 'https://leafstudio.site/'; + version = '1.0.0'; + + filters: Filters | undefined = undefined; + + parseNovelsList(cheerio: CheerioAPI): Plugin.NovelItem[] { + return cheerio('a.novel-item') + .map((i, el) => { + const elc = parseHTML(el); + return { + name: elc('p.novel-item-title').text().trim(), + path: cheerio(el).attr('href')!.replace(this.site, ''), + cover: elc('img.novel-item-Cover').attr('src'), + }; + }) + .toArray(); + } + + async popularNovels( + page: number, + { filters }: Plugin.PopularNovelsOptions, + ): Promise { + let link = this.site + 'novels'; + if (page > 1) { + link += '/page/' + page; + } + + const result = await fetchApi(link); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + return this.parseNovelsList(loadedCheerio); + } + + async parseNovel(novelPath: string): Promise { + const result = await fetchApi(this.site + novelPath); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + const novel: Plugin.SourceNovel = { + path: novelPath, + name: loadedCheerio('h1.title').text().trim() || '', + cover: loadedCheerio('img#novel_cover').attr('src') || defaultCover, + summary: loadedCheerio('div.desc_div > p') + .map((i, el) => parseHTML(el).text()) + .toArray() + .join('\n\n'), + chapters: [], + author: '', + genres: loadedCheerio('div#tags_div > a.novel_genre') + .map((i, el) => parseHTML(el).text().trim()) + .toArray() + .join(', '), + }; + const status = loadedCheerio('a#novel_status').text().trim(); + if (status == 'Active') { + novel.status = 'Ongoing'; + } else { + novel.status = status; + } + + const chapter: Plugin.ChapterItem[] = []; + + loadedCheerio('a.free_chap.chap').each((i, el) => { + const path = + loadedCheerio(el).attr('href')?.trim()?.replace(this.site, '') || ''; + const name = loadedCheerio(el).text(); + + chapter.push({ + name, + path, + }); + }); + + novel.chapters = chapter.reverse(); + + return novel; + } + + async parseChapter(chapterPath: string): Promise { + const result = await fetchApi(this.site + chapterPath); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + + return loadedCheerio('article > p.chapter_content') + .map((i, el) => parseHTML(el).html()) + .toArray() + .join('
'); + } + + async searchNovels( + searchTerm: string, + page: number, + ): Promise { + let link = this.site + 'novels'; + if (page > 1) { + link += '/page/' + page; + } + + link += + '?search=' + + encodeURIComponent(searchTerm) + + '&type=&language=&status=&sort='; + + const result = await fetchApi(link); + const body = await result.text(); + + const loadedCheerio = parseHTML(body); + return this.parseNovelsList(loadedCheerio); + } +} + +export default new LeafStudio();