Files
lnreader-plugins/plugins/japanese/Syosetu.broken.ts
T
nyagami d818d1758f Beta phase (#801)
* beta host

* Refactor: url -> path (#757)

* refactor: url -> path

* clean up

* fix: json branch

* PagePlugin (#769)

* paginated novel support

* fix: truyenfull

* fix: tunovel, remove pageList

* parsePage support for webtest (#773)

* add parsePage api

* add parsePage UI

* add totalPages

* (FR src) Beta plugin & Added filters (#775)

* noveldeglace:
 - added filters
 - added latest
 - defaultCover fallback
 - change id to noveldeglace.com
 - added complementary infos in summary
 - added cover artist
 - chapters are now parts
 - show volume number for multi volume novels
 - better search
 - fix search page number
 - refactored for plugin beta
 - releaseDate as Date.toString()
 - separted parseNovels
 - separated getCheerio
 - loadedCheerio => $ for shorter lines & simpler test on web

* chireads:
 - fix different parsing for mobile version
 - added filters
 - added author
 - added status
 - added released date
 - refactored for plugin beta
 - separted parseNovels
 - separated getCheerio
 - loadedCheerio => $ for shorter lines & simpler test on web

* wpmangastream => lightnovelwp rework & new sources (#776)

* Added sources:
 - Knoxt (EN)
 - Baca Light Novel (ID)
 - AllNovelRead (ES)
 - DaoTranslate (EN)
 - جنة الروايات (AR)
 - Universal Novel (EN)
 - NovelTR (TR)
old sources auto-generated:
 - GenesisTls (EN)
 - NobleMTL (EN)
wpmangastream => lightnovelwp:
 - added doc
 - added filters in a separte file
 - semi-automatic filter generator
 - made it compatible with version 1.0.X and 1.1.X versions of the theme
 - loadedCheerio => $
 - icons in "/icons/lightnovel/id.png"
 - code cleanup

* removed auto-implemented sources

* Added README.md to lightnovelwp

* removed ai generated text for kolnovel

* added novelsknight

* added centralNovel

* pandamtl accual name

* adding folder plugin/arabic

* Fix: Vietnamese plugins (#777)

* fix: lightnovelvn

* add nettruyen

* add truyenchu

* fix: truyenconect

* Fix: Migrate plugins (#771)

* Add novel.ovh (#756)

* fix

* test

* fix

* date fix + master merge (#761)

* date fix

* Added Brazilian Portuguese E-Novel (#758)

* fixed single digit dates (#767)

Co-authored-by: NaddH1 <naderhorani@hotmail.com>

* fix

* test

* fix order

* Update renovels.ts

* require_chapters

* Delete plugins/english/genesistl.broken.ts

* Update novelTL.ts

---------

Co-authored-by: NaddH1 <naderhorani@hotmail.com>

* (src update) ENG (#772)

* allnovelfull

* bestlightnovel

* divinedaolibrary

* earlynovel

* lightnovelpub

* L

* M

* novelbin

* novelfull

* novelbuddy

* N S

* novel updates

* async sleep

* rename file

* pagePlugin

* Feat: minify js dir (#781)

* Multisrc: HotNovelPub (#784)

* HotNovelPub

* fix search

* Squashed commit of the following:

commit 3b759c68eddc06c0adfb959f775de069a85adca7
Author: nyagami <hoangquan05112002@gmail.com>
Date:   Sat Feb 17 20:33:47 2024 +0700

    Feat: minify js dir (#781)

* jsmin changed to terser

* test

* why I did it.

* test

* Update ranobelib.ts

* fix page

* Update ranobelib.ts

* updated modules

* Update terser.json

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* Update scripts/multisrc/hotnovelpub/template.ts

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* terser api

---------

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* Added sources & fix sources (#787)

* lightnovelwp:
 - fix author name
 - added more localisation of strings
 - README typo
 - error on !r.ok new message

* noveldeglace:
 - fix chapterNumber for parts
 - better dates
 - better search

* Added sources:
 - White Moonlight Novels (EN)
 - System Translation (EN)

* Resized centralnovel.png

* Add Faqwiki.us source (#792)

* Add Faqwiki.us source (beta branch)

* Fix Path, Fix Chapter Parsing, Fix Novel Title

* search novel path fix

* fix chapter parsing. some chapter in this site store their whole text in 1-4 <p>,

* Add WTR-LAB Source (#797)

* Add WTR-LAB Source (Beta Branch)

* Add other language from WTR-LAB source

* change lang to sourceLang

* remove id es tr lang from WTR-LAB

* Update plugins/english/wtrlab.ts

agree

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* Update plugins/english/wtrlab.ts

agree

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

---------

Co-authored-by: nyagami <hoangquan05112002@gmail.com>

* revert: scripts to master

---------

Co-authored-by: Justin COLLON <48163201+error7404@users.noreply.github.com>
Co-authored-by: Rider21 <58046032+Rider21@users.noreply.github.com>
Co-authored-by: NaddH1 <naderhorani@hotmail.com>
Co-authored-by: K1ngfish3r <trulyihu@gmail.com>
Co-authored-by: bregassa <bregas.sat1@gmail.com>
2024-02-25 14:52:37 +07:00

285 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { load, load as loadCheerio } from "cheerio";
import { fetchApi, fetchFile } from "@libs/fetch";
import { Plugin } from "@typings/plugin";
import { defaultCover } from "@libs/defaultCover";
import { FilterTypes, Filters } from "@libs/filterInputs";
import { NovelItem } from "../../test_web/static/js";
// const novelStatus = require('@libs/novelStatus');
// const isUrlAbsolute = require('@libs/isAbsoluteUrl');
// const parseDate = require('@libs/parseDate');
class Syosetu implements Plugin.PluginBase {
id = "yomou.syosetu";
name = "Syosetu";
icon = "src/jp/syosetu/icon.png";
site = "https://yomou.syosetu.com/";
version = "1.1.0";
headers = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
};
searchUrl = (pagenum?: number, order?: string) => {
return `https://yomou.syosetu.com/search.php?order=${order || "hyoka"}${
pagenum !== undefined
? `&p=${pagenum <= 1 || pagenum > 100 ? "1" : pagenum}` // check if pagenum is between 1 and 100
: "" // if isn't don't set ?p
}`;
};
async popularNovels(
pageNo: number,
{ filters }: Plugin.PopularNovelsOptions<typeof this.filters>
): Promise<Plugin.NovelItem[]> {
const getNovelsFromPage = async (pagenumber: number) => {
// load page
let url = this.site;
if (!filters.genre.value) {
url += `rank/list/type/${filters.ranking.value}_${filters.modifier.value}/?p=${pagenumber}`;
} else {
url += `rank/${
filters.genre.value.length === 1
? "isekailist"
: "genrelist"
}/type/${filters.ranking.value}_${filters.genre.value}${
filters.modifier.value === "total"
? ""
: `_${filters.modifier.value}`
}/?p=${pagenumber}`;
}
const html = await (await fetchApi(url)).text();
const loadedCheerio = loadCheerio(html, {
decodeEntities: false,
});
if (
parseInt(loadedCheerio(".is-current").html() || "1") !==
pagenumber
)
return [];
const novels: NovelItem[] = [];
loadedCheerio(".c-card").each((_, e) => {
const anchor = loadedCheerio(e).find(
".p-ranklist-item__title a"
);
const url = anchor.attr("href");
if (!url) return;
const name = anchor.text();
const novel: NovelItem = {
url,
name,
cover: defaultCover,
};
novels.push(novel);
});
return novels;
};
const novels = await getNovelsFromPage(pageNo);
return novels;
}
async parseNovelAndChapters(novelUrl: string): Promise<Plugin.SourceNovel> {
let chapters: Plugin.ChapterItem[] = [];
const result = await fetch(novelUrl, { headers: this.headers });
const body = await result.text();
const loadedCheerio = loadCheerio(body, { decodeEntities: false });
// create novel object
let novel: Plugin.SourceNovel = {
url: novelUrl,
name: loadedCheerio(".novel_title").text(),
author: loadedCheerio(".novel_writername")
.text()
.replace("作者:", ""),
cover: defaultCover,
};
// Get all the chapters
const cqGetChapters = loadedCheerio(".novel_sublist2");
if (cqGetChapters.length !== 0) {
// has more than 1 chapter
novel.summary = loadedCheerio("#novel_ex")
.text()
.replace(/<\s*br.*?>/g, "\n");
cqGetChapters.each(function (i, e) {
const chapterA = loadedCheerio(this).find("a");
const [chapterName, releaseDate, chapterUrl] = [
// set the variables
chapterA.text(),
loadedCheerio(this)
.find("dt") // get title
.text() // get text
.replace(/(.)/g, "") // remove "(edited)" mark
.trim(), // trim spaces
"https://ncode.syosetu.com" + chapterA.attr("href"),
];
chapters.push({
name: chapterName,
releaseTime: releaseDate,
url: chapterUrl,
});
});
} else {
/**
* Because there are oneshots on the site, they have to be treated with special care
* that's what pisses me off in Shosetsu app. They have this extension,
* but every oneshot is set as "there are no chapters" and all contents are thrown into the description!!
*/
// get summary for oneshot chapter
const nameResult = await fetch(
this.searchUrl() + `&word=${novel.name}`,
{ headers: this.headers }
);
const nameBody = await nameResult.text();
const summaryQuery = loadCheerio(nameBody, {
decodeEntities: false,
});
const foundText = summaryQuery(".searchkekka_box")
.first()
.find(".ex")
.text()
.replace(/\s{2,}/g, "\n");
novel.summary = foundText;
// add single chapter
chapters.push({
name: "Oneshot",
releaseTime: loadedCheerio("head")
.find("meta[name='WWWC']")
.attr("content"), // get date from metadata
url: novelUrl, // set chapterUrl to oneshot so that chapterScraper knows it's a one-shot,
});
}
novel.chapters = chapters;
return novel;
}
async parseChapter(chapterUrl: string): Promise<string> {
const result = await fetch(chapterUrl, { headers: this.headers });
const body = await result.text();
// create cheerioQuery
const cheerioQuery = loadCheerio(body, {
decodeEntities: false,
});
let chapterText =
cheerioQuery("#novel_honbun") // get chapter text
.html() || "";
return chapterText;
}
async searchNovels(
searchTerm: string,
pageNo: number
): Promise<Plugin.NovelItem[]> {
let novels = [];
// returns list of novels from given page
const getNovelsFromPage = async (pagenumber: number) => {
// load page
const url = this.searchUrl(pagenumber) + `&word=${searchTerm}`;
console.log(url);
const result = await fetch(url, { headers: this.headers });
const body = await result.text();
// Cheerio it!
const cheerioQuery = loadCheerio(body, { decodeEntities: false });
let pageNovels: Plugin.NovelItem[] = [];
// find class=searchkekka_box
cheerioQuery(".searchkekka_box").each(function (i, e) {
// get div with link and name
const novelDIV = cheerioQuery(this).find(".novel_h");
// get link element
const novelA = novelDIV.children()[0];
// add new novel to array
pageNovels.push({
name: novelDIV.text(), // get the name
url: novelA.attribs.href, // get last part of the link
cover: defaultCover,
});
});
// return all novels from this page
return pageNovels;
};
// counter of loaded pages
// let pagesLoaded = 0;
// do {
// // always load first one
// novels.push(...(await getNovelsFromPage(pagesLoaded + 1)));
// pagesLoaded++;
// } while (pagesLoaded < maxPageLoad && isNext); // check if we should load more
novels = await getNovelsFromPage(pageNo);
/** Use
* novels.push(...(await getNovelsFromPage(pageNumber)))
* if you want to load more
*/
// respond with novels!
return novels;
}
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = {
ranking: {
type: FilterTypes.Picker,
label: "Ranked by",
options: [
{ label: "日間", value: "daily" },
{ label: "週間", value: "weekly" },
{ label: "月間", value: "monthly" },
{ label: "四半期", value: "quarter" },
{ label: "年間", value: "yearly" },
{ label: "累計", value: "total" },
],
value: "total",
},
genre: {
type: FilterTypes.Picker,
label: "Ranking Genre",
options: [
{ label: "総ジャンル", value: "" },
{ label: "異世界転生/転移〔恋愛〕〕", value: "1" },
{ label: "異世界転生/転移〔ファンタジー〕", value: "2" },
{ label: "異世界転生/転移〔文芸・SF・その他〕", value: "o" },
{ label: "異世界〔恋愛〕", value: "101" },
{ label: "現実世界〔恋愛〕", value: "102" },
{ label: "ハイファンタジー〔ファンタジー〕", value: "201" },
{ label: "ローファンタジー〔ファンタジー〕", value: "202" },
{ label: "純文学〔文芸〕", value: "301" },
{ label: "ヒューマンドラマ〔文芸〕", value: "302" },
{ label: "歴史〔文芸〕", value: "303" },
{ label: "推理〔文芸〕", value: "304" },
{ label: "ホラー〔文芸〕", value: "305" },
{ label: "アクション〔文芸〕", value: "306" },
{ label: "コメディー〔文芸〕", value: "307" },
{ label: "VRゲーム〔SF〕", value: "401" },
{ label: "宇宙〔SF〕", value: "402" },
{ label: "空想科学〔SF〕", value: "403" },
{ label: "パニック〔SF〕", value: "404" },
{ label: "童話〔その他〕", value: "9901" },
{ label: "詩〔その他〕", value: "9902" },
{ label: "エッセイ〔その他〕", value: "9903" },
{ label: "その他〔その他〕", value: "9999" },
],
value: "",
},
modifier: {
type: FilterTypes.Picker,
label: "Modifier",
options: [
{ label: "すべて", value: "total" },
{ label: "連載中", value: "r" },
{ label: "完結済", value: "er" },
{ label: "短編", value: "t" },
],
value: "total",
},
} satisfies Filters;
}
export default new Syosetu();