From 6332d37a0d56c86a24136e967342de8cd941ba05 Mon Sep 17 00:00:00 2001 From: "The Couch Potato (on Mars)" <116996397+martian-potato@users.noreply.github.com> Date: Tue, 23 Dec 2025 16:20:19 +0600 Subject: [PATCH] feat: Add Crimson Scrolls (#1930) Closes #1851 Signed-off-by: Martian Potato <2260cse01024@manarat.ac.bd> --- plugins/english/crimsonscrolls.ts | 183 +++++++++++++++++++ public/static/src/en/crimsonscrolls/icon.png | Bin 0 -> 16209 bytes 2 files changed, 183 insertions(+) create mode 100644 plugins/english/crimsonscrolls.ts create mode 100644 public/static/src/en/crimsonscrolls/icon.png diff --git a/plugins/english/crimsonscrolls.ts b/plugins/english/crimsonscrolls.ts new file mode 100644 index 0000000..fef8bbe --- /dev/null +++ b/plugins/english/crimsonscrolls.ts @@ -0,0 +1,183 @@ +import { CheerioAPI, load as parseHTML } from 'cheerio'; +import { fetchApi } from '@libs/fetch'; +import { FilterTypes, Filters } from '@libs/filterInputs'; +import { Plugin } from '@/types/plugin'; +import { storage } from '@libs/storage'; +import dayjs from 'dayjs'; + +enum APIAction { + novels = 'load_novels', + search = 'live_novel_search', +} + +interface APIParams { + action: APIAction; + params: Record; +} + +class CrimsonScrollsPlugin implements Plugin.PluginBase { + id = 'crimsonscrolls'; + name = 'Crimson Scrolls'; + icon = 'src/en/crimsonscrolls/icon.png'; + site = 'https://crimsonscrolls.net'; + version = '1.0.0'; + + hideLocked = storage.get('hideLocked'); + pluginSettings = { + hideLocked: { + value: '', + label: 'Hide locked chapters', + type: 'Switch', + }, + }; + + async queryAPI(query: APIParams): Promise { + const formData = new FormData(); + formData.append('action', query.action); + for (const [key, value] of Object.entries(query.params)) + formData.append(key, value); + + const result = await fetchApi(`${this.site}/wp-admin/admin-ajax.php`, { + method: 'POST', + body: formData, + }).then(result => result.json()); + + return parseHTML(result.html); + } + + async fetchChapters(id: number, page?: number | undefined) { + const chapter: any[] = []; + const url = `${this.site}/wp-json/cs/v1/novels/${id}/chapters?per_page=75&order=asc`; //page=${page} + const data = await fetchApi(`${url}&page=${page || 1}`).then(r => r.json()); + const locked = data.items.some(e => e.locked); + + if (data.page < data.total_pages && !(locked && this.hideLocked)) + return data.items.concat( + await this.fetchChapters(id, parseInt(data.page) + 1), + ); + else return data.items; + } + + parseNovels(loadedCheerio: CheerioAPI) { + const novels: Plugin.NovelItem[] = []; + + loadedCheerio(':is(a.live-search-item, div.novel-list-card)').each( + (i, el) => { + const novelName = loadedCheerio(el) + .find(':is(div.live-search-title, h3.novel-title)') + .text() + .trim(); + const novelCover = loadedCheerio(el) + .find(':is(img.live-search-cover, div.novel-cover img)') + .attr('src'); + const novelUrl = + loadedCheerio(el).find('a').attr('href') || + loadedCheerio(el).attr('href'); + + if (!novelUrl) return; + + const novel = { + name: novelName + .trim() + .split(' ') + .filter(e => e.length > 0) + .join(' '), + cover: novelCover, + path: novelUrl.replace(this.site, '').split('/').at(2), + }; + novels.push(novel); + }, + ); + return novels; + } + + async popularNovels(page: number): Promise { + const loadedCheerio = await this.queryAPI({ + action: APIAction.novels, + params: { page: page as string }, + }); + return this.parseNovels(loadedCheerio); + } + + async parseNovel(novelPath: string): Promise { + const result = await fetchApi(`${this.site}/novel/${novelPath}`).then(r => + r.text(), + ); + + let loadedCheerio = parseHTML(result); + let novelInfo = loadedCheerio('#single-novel-content-wrapper'); + + const novel: Plugin.SourceNovel = { + path: novelPath, + name: novelInfo.find('h1.chapter-title').text().trim() || 'Untitled', + cover: novelInfo.find('.single-novel-cover > img').data('src'), + summary: novelInfo.find('#synopsis-full').text().trim(), + author: novelInfo + .find('.single-novel-meta strong') + .filter( + (i, el) => + loadedCheerio(el).text().toLowerCase().search('author') >= 0, + )[0] + .next.data.trim(), + chapters: [], + }; + + novel.genres = novelInfo + .find('.single-novel-meta strong') + .filter( + (i, el) => loadedCheerio(el).text().toLowerCase().search('genre') >= 0, + )[0] + .next.data.split(',') + .map(e => e.trim()) + .join(','); + + novel.status = 'Unknown'; + const id = loadedCheerio('#chapter-list').data('novel'); + const chapters = await this.fetchChapters(id); + + novel.chapters = []; + for (const idx in chapters) { + if (!(chapters[idx].locked && this.hideLocked)) { + novel.chapters.push({ + name: chapters[idx].locked + ? `🔒 ${chapters[idx].title}` + : chapters[idx].title, + path: chapters[idx].url.replace(this.site, '').split('/').at(2), + chapterNumber: parseInt(idx) + 1, + }); + } + } + + return novel; + } + + async parseChapter(chapterPath: string): Promise { + const body = await fetchApi(`${this.site}/chapter/${chapterPath}`).then(r => + r.text(), + ); + const loadedCheerio = parseHTML(body); + for (const i of [ + 'hr.cs-attrib-divider', + 'div.cs-attrib', + 'p.cs-chapter-attrib', + ]) + loadedCheerio(`#chapter-display ${i}:last`).remove(); + + const chapterText = loadedCheerio('#chapter-display').html() || ''; + return chapterText; + } + + async searchNovels(searchTerm: string): Promise { + const loadedCheerio = await this.queryAPI({ + action: APIAction.search, + params: { query: searchTerm }, + }); + + return this.parseNovels(loadedCheerio); + } + + resolveUrl = (path: string, isNovel?: boolean) => + this.site + '/novel/' + path; +} + +export default new CrimsonScrollsPlugin(); diff --git a/public/static/src/en/crimsonscrolls/icon.png b/public/static/src/en/crimsonscrolls/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bfadff509f55e3242642cfd0d19256b26ff23fab GIT binary patch literal 16209 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 literal 0 HcmV?d00001