const dataPage = cheerioInstance('#app').attr('data-page');
if (!dataPage) {
throw new Error('data-page attribute not found on Bright Novels.');
}
// Parse the JSON from data-page
let pageData;
try {
pageData = JSON.parse(dataPage) as {
component: string;
props: {
chapter: {
id: number;
title: string;
content: string;
};
};
};
} catch (e) {
throw new Error(
'Failed to parse data-page JSON for Bright Novels.',
);
}
const chapterTitle = pageData.props.chapter.title;
let chapterContent = pageData.props.chapter.content;
// Clean up content (remove inline styles/scripts if needed)
const chapterCheerio = parseHTML(chapterContent);
chapterCheerio('script, style').remove();
chapterContent = chapterCheerio.html()!;
// Return formatted HTML
return `
${chapterTitle}
${chapterContent}`;
};
try {
chapterText = extractBrightNovelsContent(loadedCheerio);
} catch (err) {
// Fallback: try to extract whatever is in #app or body
let fallbackContent =
loadedCheerio('#app').html() || loadedCheerio('body').html() || '';
// Remove scripts/styles
const fallbackCheerio = parseHTML(fallbackContent);
fallbackCheerio('script, style').remove();
fallbackContent = fallbackCheerio.html()!;
chapterText = fallbackContent;
}
break;
}
// Last edited in 0.9.2 by Batorian - 08/09/2025
case 'canonstory': {
try {
const parts = chapterPath.split('/');
if (parts.length < 7) {
throw new Error('Invalid chapter URL structure');
}
const novelSlug = parts[4];
const chapterSlug = parts[6];
const url = `${parts[0]}//${parts[2]}/api/public/chapter-by-slug/${novelSlug}/${chapterSlug}`;
const response = await fetchApi(url);
const json = await response.json();
if (!json?.data?.currentChapter) {
throw new Error('Invalid API response structure.');
}
const data = json.data.currentChapter;
const { chapterNumber, title, content } = data;
const titleElement = `Chapter ${chapterNumber}`;
chapterTitle = title ? `${titleElement} - ${title}` : titleElement;
chapterContent = content.replace(/\n/g, '
');
break;
} catch (error) {
throw new Error(`Failed to parse Canon Story chapter: ${error}`);
}
}
// Last edited in 0.9.3 by Batorian - 09/09/2025
case 'daoist': {
chapterTitle = loadedCheerio('.chapter__title').first().text();
// Remove locked content indicators
loadedCheerio('span.patreon-lock-icon').remove();
// Handle lazy-loaded images
loadedCheerio('img[data-src]').each((_, el) => {
const $el = loadedCheerio(el);
const dataSrc = $el.attr('data-src');
if (dataSrc) {
$el.attr('src', dataSrc);
$el.removeAttr('data-src');
}
});
chapterContent = loadedCheerio('.chapter__content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'fictionread': {
bloatElements = [
'.content > style',
'.highlight-ad-container',
'.meaning',
'.word',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('.title-image span').first().text();
loadedCheerio('.content')
.children()
.each((_, el) => {
if (loadedCheerio(el).attr('id')?.includes('Chaptertitle-info')) {
loadedCheerio(el).remove();
return false;
}
});
chapterContent = loadedCheerio('.content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'genesistudio': {
const url = `${chapterPath}/__data.json?x-sveltekit-invalidated=001`;
try {
// Fetch the chapter's data in JSON format
const json = await fetchApi(url).then(r => r.json());
const nodes = json.nodes;
const data = nodes
.filter((node: { type: string }) => node.type === 'data')
.map((node: { data: any }) => node.data)[0];
// Look for chapter container with required fields
const contentKey = 'content';
const notesKey = 'notes';
const footnotesKey = 'footnotes';
// Iterate over each property in data to find chapter containers
for (const key in data) {
const mapping = data[key];
// Check container for keys that match the required fields
if (
mapping &&
typeof mapping === 'object' &&
contentKey in mapping &&
notesKey in mapping &&
footnotesKey in mapping
) {
// Retrieve the chapter's content, notes, and footnotes using the mapping.
const content = data[mapping[contentKey]];
const notes = data[mapping[notesKey]];
const footnotes = data[mapping[footnotesKey]];
// Combine the parts with appropriate formatting
chapterText =
content +
(notes ? `
Notes
${notes}` : '') +
(footnotes ?? '');
break;
}
}
} catch (error) {
throw new Error(`Failed to fetch chapter data: ${error}`);
}
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'helscans': {
chapterTitle = loadedCheerio('.entry-title-main').first().text();
const chapterString_helscans =
'Chapter ' + chapterTitle.split('Chapter')[1].trim();
loadedCheerio('#readerarea.rdminimal')
.children()
.each((_, el) => {
const elementText = loadedCheerio(el).text();
if (elementText.includes(chapterString_helscans)) {
chapterTitle = elementText;
loadedCheerio(el).remove();
return false;
}
});
chapterContent = loadedCheerio('#readerarea.rdminimal').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'hiraethtranslation': {
chapterTitle = loadedCheerio('li.active').first().text();
chapterContent = loadedCheerio('.text-left').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'hostednovel': {
chapterTitle = loadedCheerio('#chapter-title').first().text();
chapterContent = loadedCheerio('#chapter-content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'infinitenoveltranslations': {
// Get the chapter link from the main page
const url = loadedCheerio('article > p > a').first().attr('href')!;
if (url) {
const response = await fetchApi(url);
const body = await response.text();
loadedCheerio = parseHTML(body);
}
chapterContent = loadedCheerio('.hentry').html()!;
chapterTitle = loadedCheerio('.page-entry-title').text();
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'inoveltranslation': {
bloatElements = ['header', 'section'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterText = loadedCheerio('.styles_content__JHK8G').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
// mii translates
case 'isotls': {
bloatElements = [
'footer',
'header',
'nav',
'.ezoic-ad',
'.ezoic-adpicker-ad',
'.ezoic-videopicker-video',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('head title').first().text();
chapterContent = loadedCheerio('main article').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'ko-fi': {
const matchResult = loadedCheerio(
'script:contains("shadowDom.innerHTML")',
)
.html()
?.match(/shadowDom\.innerHTML \+= '(
loadedCheerio(tag).remove());
const titleElement = loadedCheerio('.entry-content p strong').first();
chapterTitle = titleElement.text();
titleElement.remove();
chapterContent = loadedCheerio('.entry-content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'novelplex': {
bloatElements = ['.passingthrough_adreminder'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('.halChap--jud').first().text();
chapterContent = loadedCheerio('.halChap--kontenInner ').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'novelworldtranslations': {
bloatElements = ['.separator img'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
loadedCheerio('.entry-content a')
.filter((_, el) => {
return (
loadedCheerio(el)
.attr('href')
?.includes('https://novelworldtranslations.blogspot.com') ||
false
);
})
.each((_, el) => {
loadedCheerio(el).parent().remove();
});
chapterTitle = loadedCheerio('.entry-title').first().text();
chapterContent = loadedCheerio('.entry-content')
.html()!
.replace(/ /g, '')
.replace(/\n/g, '
');
// Load the chapter content into Cheerio and clean up empty elements
const chapterCheerio = parseHTML(chapterContent);
chapterCheerio('span, p, div').each((_, el) => {
if (chapterCheerio(el).text().trim() === '') {
chapterCheerio(el).remove();
}
});
chapterContent = chapterCheerio.html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'raeitranslations': {
const parts = chapterPath.split('/');
const url = `${parts[0]}//api.${parts[2]}/api/chapters/single?id=${parts[3]}&num=${parts[4]}`;
const json = await fetchApi(url).then(r => r.json());
const titleElement = `Chapter ${json.currentChapter.chapTag}`;
chapterTitle = json.currentChapter.chapTitle
? `${titleElement} - ${json.currentChapter.chapTitle}`
: titleElement;
chapterContent = [
json.novelHead,
`
`,
json.currentChapter.body,
`
Translator's Note:
`,
json.currentChapter.note,
].join('');
chapterContent = chapterContent.replace(/\n/g, '
');
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'rainofsnow': {
const displayedDiv = loadedCheerio('.bb-item').filter(function () {
return loadedCheerio(this).css('display') === 'block';
});
const loadedCheerioSnow = parseHTML(displayedDiv.html()!);
bloatElements = [
'.responsivevoice-button',
'.zoomdesc-cont p img',
'.zoomdesc-cont p noscript',
];
bloatElements.forEach(tag => loadedCheerioSnow(tag).remove());
chapterContent = loadedCheerioSnow('.zoomdesc-cont').html()!;
const titleElement = loadedCheerioSnow('.scroller h2').first();
if (titleElement.length) {
chapterTitle = titleElement.text();
titleElement.remove();
chapterContent = loadedCheerioSnow('.zoomdesc-cont').html()!;
}
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'readingpia': {
bloatElements = ['.ezoic-ad', '.ezoic-adpicker-ad', '.ez-video-wrap'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterText = loadedCheerio('.chapter-body').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'redoxtranslation': {
const chapterId = chapterPath.split('/').pop();
chapterTitle = `Chapter ${chapterId}`;
const url = `${chapterPath.split('chapter')[0]}txt/${chapterId}.txt`;
chapterContent = await fetchApi(url)
.then(r => r.text())
.then(text => {
// Split text into sentences based on newline characters
const sentences = text.split('\n');
// Process each sentence individually
const formattedSentences = sentences.map(sentence => {
// Check if the sentence contains "
"
if (sentence.includes('{break}')) {
// Create a centered sentence with three stars
return '
****
';
} else {
// Replace text enclosed within ** with tags
sentence = sentence.replace(
/\*\*(.*?)\*\*/g,
'$1',
);
// Replace text enclosed within ++ with tags
sentence = sentence.replace(/\+\+(.*?)\+\+/g, '$1');
return sentence;
}
});
// Join the formatted sentences back together with newline characters
return formattedSentences.join('
');
});
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'sacredtexttranslations': {
bloatElements = [
'.entry-content blockquote',
'.entry-content div',
'.reaction-buttons',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('.entry-title').first().text();
chapterContent = loadedCheerio('.entry-content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'scribblehub': {
bloatElements = ['.wi_authornotes'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('.chapter-title').first().text();
chapterContent = loadedCheerio('.chp_raw').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'skydemonorder': {
// Check for age verification
const ageVerification = loadedCheerio('main').text().toLowerCase()!;
if (ageVerification.includes('age verification required')) {
throw new Error('Age verification required, please open in webview.');
}
chapterTitle = `${loadedCheerio('header .font-medium.text-sm').first().text().trim()}`;
chapterContent = loadedCheerio('#chapter-body').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'stabbingwithasyringe': {
// Get the chapter link from the main page
const url = loadedCheerio('.entry-content a').attr('href')!;
if (url) {
const response = await fetchApi(url);
const body = await response.text();
loadedCheerio = parseHTML(body);
}
bloatElements = [
'.has-inline-color',
'.wp-block-buttons',
'.wpcnt',
'#jp-post-flair',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterContent = loadedCheerio('.entry-content').html()!;
const titleElement = loadedCheerio('.entry-content h3').first();
if (titleElement.length) {
chapterTitle = titleElement.text();
titleElement.remove();
chapterContent = loadedCheerio('.entry-content').html()!;
}
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'tinytranslation': {
bloatElements = [
'.content noscript',
'.google_translate_element',
'.navigate',
'.post-views',
'br',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('.title-content').first().text();
loadedCheerio('.title-content').first().remove();
chapterContent = loadedCheerio('.content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'tumblr': {
chapterText = loadedCheerio('.post').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'vampiramtl': {
// Get the chapter link from the main page
const url = loadedCheerio('.entry-content a').attr('href')!;
if (url) {
const response = await fetchApi(chapterPath + url);
const body = await response.text();
loadedCheerio = parseHTML(body);
}
chapterTitle = loadedCheerio('.entry-title').first().text();
chapterContent = loadedCheerio('.entry-content').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'wattpad': {
chapterTitle = loadedCheerio('.h2').first().text();
chapterContent = loadedCheerio('.part-content pre').html()!;
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'webnovel': {
chapterTitle = loadedCheerio('.cha-tit .pr .dib').first().text();
chapterContent = loadedCheerio('.cha-words').html()!;
if (!chapterContent) {
chapterContent = loadedCheerio('._content').html()!;
}
break;
}
case 'wetriedtls': {
const scriptContent =
loadedCheerio('script:contains("p dir=")').html() ||
loadedCheerio('script:contains("u003c")').html();
if (scriptContent) {
const jsonString_wetried = scriptContent.slice(
scriptContent.indexOf('.push(') + '.push('.length,
scriptContent.lastIndexOf(')'),
);
chapterText = JSON.parse(jsonString_wetried)[1];
}
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'wuxiaworld': {
bloatElements = ['.MuiLink-root'];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
chapterTitle = loadedCheerio('h4 span').first().text();
chapterContent = loadedCheerio('.chapter-content').html()!;
break;
}
case 'yoru': {
const chapterId = chapterPath.split('/').pop();
const url = `https://pxp-main-531j.onrender.com/api/v1/book_chapters/${chapterId}/content`;
const json = await fetchApi(url).then(r => r.json());
chapterText = await fetchApi(json).then(r => r.text());
break;
}
// Last edited in 0.9.0 by Batorian - 19/03/2025
case 'zetrotranslation': {
chapterContent = loadedCheerio('.text-left').html()!;
const titleElement = loadedCheerio('.text-left h2').first();
if (titleElement.length) {
chapterTitle = titleElement.text();
titleElement.remove();
chapterContent = loadedCheerio('.text-left').html()!;
} else if (chapterContent) {
chapterTitle = loadedCheerio('.active').first().text();
}
break;
}
}
if (!chapterText) {
if (chapterTitle) {
chapterText = `${chapterTitle}
${chapterContent}`;
} else {
chapterText = chapterContent;
}
}
return chapterText;
}
async parseChapter(chapterPath: string): Promise {
let chapterText;
const response = await fetchApi(this.site + chapterPath);
const body = await response.text();
const url = response.url;
const domainParts = url.toLowerCase().split('/')[2].split('.');
const loadedCheerio = parseHTML(body);
// Handle CAPTCHA cases
const blockedTitles = [
'bot verification',
'just a moment...',
'redirecting...',
'un instant...',
'you are being redirected...',
];
const title = loadedCheerio('title').text().trim().toLowerCase();
if (blockedTitles.includes(title)) {
throw new Error('Captcha detected, please open in webview.');
}
// Check if chapter url is wrong or site is down
if (!response.ok) {
throw new Error(
`Failed to fetch ${response.url}: ${response.status} ${response.statusText}`,
);
}
// Detect platforms
let isBlogspot = ['blogspot', 'blogger'].some(keyword =>
[
loadedCheerio('meta[name="google-adsense-platform-domain"]').attr(
'content',
),
loadedCheerio('meta[name="generator"]').attr('content'),
].some(meta => meta?.toLowerCase().includes(keyword)),
);
let isWordPress = ['wordpress', 'site kit by google'].some(keyword =>
[
loadedCheerio('#dcl_comments-js-extra').html(),
loadedCheerio('meta[name="generator"]').attr('content'),
loadedCheerio('.powered-by').text(),
loadedCheerio('footer').text(),
].some(meta => meta?.toLowerCase().includes(keyword)),
);
// Manually set WordPress flag for known sites
const manualWordPress = ['etherreads', 'greenztl2', 'soafp'];
if (!isWordPress && domainParts.some(wp => manualWordPress.includes(wp))) {
isWordPress = true;
}
// Handle outlier sites
const outliers = [
'anotivereads',
'arcanetranslations',
'asuratls',
'fictionread',
'helscans',
'hiraethtranslation',
'infinitenoveltranslations',
'machineslicedbread',
'mirilu',
'novelworldtranslations',
'sacredtexttranslations',
'stabbingwithasyringe',
'tinytranslation',
'vampiramtl',
'zetrotranslation',
];
if (domainParts.some(d => outliers.includes(d))) {
isWordPress = false;
isBlogspot = false;
}
// Last edited in 0.9.2 - 08/09/2025
/**
* Blogspot sites:
* - ¼-Assed
* - AsuraTls (Outlier)
* - FictionRead (Outlier)
* - Novel World Translations (Outlier)
* - SacredText TL (Outlier)
* - Toasteful
*
* WordPress sites:
* - Anomlaously Creative (Outlier)
* - Arcane Translations (Outlier)
* - Blossom Translation
* - Dumah's Translations
* - ElloMTL
* - Ether Reads
* - Femme Fables
* - Gadgetized Panda Translation
* - Gem Novels
* - Goblinslate
* - Hel Scans (Outlier)
* - Hiraeth Translation (Outlier)
* - ippotranslations
* - JATranslations
* - Light Novels Translations
* - Machine Sliced Bread (Outlier)
* - Mirilu - Novel Reader Attempts Translating (Outlier)
* - Neosekai Translations
* - Noice Translations
* - Shanghai Fantasy
* - Soafp (Manually added)
* - Stabbing with a Syringe (Outlier)
* - StoneScape
* - TinyTL (Outlier)
* - VampiraMTL (Outlier)
* - Wonder Novels
* - Yong Library
* - Zetro Translation (Outlier)
*/
// Fetch chapter content based on detected platform
if (!isWordPress && !isBlogspot) {
chapterText = await this.getChapterBody(loadedCheerio, domainParts, url);
} else {
const bloatElements = isBlogspot
? ['.button-container', '.ChapterNav', '.ch-bottom', '.separator']
: [
'.ad',
'.author-avatar',
'.chapter-warning',
'.entry-meta',
'.ezoic-ad',
'.mb-center',
'.modern-footnotes-footnote__note',
'.patreon-widget',
'.post-cats',
'.pre-bar',
'.sharedaddy',
'.sidebar',
'.swg-button-v2-light',
'.wp-block-buttons',
//'.wp-block-columns',
'.wp-dark-mode-switcher',
'.wp-next-post-navi',
'#hpk',
'#jp-post-flair',
'#textbox',
];
bloatElements.forEach(tag => loadedCheerio(tag).remove());
// Extract title
const titleSelectors = isBlogspot
? ['.entry-title', '.post-title', 'head title']
: [
'.entry-title',
'.chapter__title',
'.title-content',
'.wp-block-post-title',
'.title_story',
'#chapter-heading',
'.chapter-title',
'head title',
'h1:first-of-type',
'h2:first-of-type',
'.active',
];
let chapterTitle = titleSelectors
.map(sel => loadedCheerio(sel).first().text())
.find(text => text);
// Extract subtitle (if any)
const chapterSubtitle =
loadedCheerio('.cat-series').first().text() ||
loadedCheerio('h1.leading-none ~ span').first().text();
if (chapterSubtitle) chapterTitle = chapterSubtitle;
// Extract content
const contentSelectors = isBlogspot
? ['.content-post', '.entry-content', '.post-body']
: [
'.chapter__content',
'.entry-content',
'.text_story',
'.post-content',
'.contenta',
'.single_post',
'.main-content',
'.reader-content',
'#content',
'#the-content',
'article.post',
'.chp_raw',
];
const chapterContent = contentSelectors
.map(sel => loadedCheerio(sel).html()!)
.find(html => html);
if (chapterTitle && chapterContent) {
chapterText = `${chapterTitle}
${chapterContent}`;
} else {
chapterText = chapterContent;
}
}
// Fallback content extraction
if (!chapterText) {
['nav', 'header', 'footer', '.hidden'].forEach(tag =>
loadedCheerio(tag).remove(),
);
chapterText = loadedCheerio('body').html()!;
}
// Convert relative URLs to absolute
chapterText = chapterText.replace(
/href="\//g,
`href="${this.getLocation(response.url)}/`,
);
// Process images
const chapterCheerio = parseHTML(chapterText);
chapterCheerio('noscript').remove();
chapterCheerio('img').each((_, el) => {
const $el = chapterCheerio(el);
// Only update if the lazy-loaded attribute exists
if ($el.attr('data-lazy-src')) {
$el.attr('src', $el.attr('data-lazy-src'));
}
if ($el.attr('data-lazy-srcset')) {
$el.attr('srcset', $el.attr('data-lazy-srcset'));
}
// Remove lazy-loading class if it exists
if ($el.hasClass('lazyloaded')) {
$el.removeClass('lazyloaded');
}
});
return chapterCheerio.html()!;
}
async searchNovels(
searchTerm: string,
page: number,
): Promise {
// Split searchTerm by specific special characters and find the longest split
const splits = searchTerm.split('*');
const longestSearchTerm = splits.reduce(
(a, b) => (a.length > b.length ? a : b),
'',
);
searchTerm = longestSearchTerm.replace(/[‘’]/g, "'").replace(/\s+/g, '+');
const url = `${this.site}series-finder/?sf=1&sh=${searchTerm}&sort=srank&order=asc&pg=${page}`;
const response = await fetchApi(url);
const body = await response.text();
const loadedCheerio = parseHTML(body);
return this.parseNovels(loadedCheerio);
}
filters = {
sort: {
label: 'Sort Results By',
value: 'popmonth',
options: [
{ label: 'Popular (Month)', value: 'popmonth' },
{ label: 'Popular (All)', value: 'popular' },
{ label: 'Last Updated', value: 'sdate' },
{ label: 'Rating', value: 'srate' },
{ label: 'Rank', value: 'srank' },
{ label: 'Reviews', value: 'sreview' },
{ label: 'Chapters', value: 'srel' },
{ label: 'Title', value: 'abc' },
{ label: 'Readers', value: 'sread' },
{ label: 'Frequency', value: 'sfrel' },
],
type: FilterTypes.Picker,
},
order: {
label: 'Order (Not for Popular)',
value: 'desc',
options: [
{ label: 'Descending', value: 'desc' },
{ label: 'Ascending', value: 'asc' },
],
type: FilterTypes.Picker,
},
storyStatus: {
label: 'Story Status (Translation)',
value: '',
options: [
{ label: 'All', value: '' },
{ label: 'Completed', value: '2' },
{ label: 'Ongoing', value: '3' },
{ label: 'Hiatus', value: '4' },
],
type: FilterTypes.Picker,
},
genre_operator: {
label: 'Genre (And/Or) (Not for Popular)',
value: 'and',
options: [
{ label: 'And', value: 'and' },
{ label: 'Or', value: 'or' },
],
type: FilterTypes.Picker,
},
genres: {
label: 'Genres',
type: FilterTypes.ExcludableCheckboxGroup,
value: {
include: [],
exclude: [],
},
options: [
{ label: 'Action', value: '8' },
{ label: 'Adult', value: '280' },
{ label: 'Adventure', value: '13' },
{ label: 'Comedy', value: '17' },
{ label: 'Drama', value: '9' },
{ label: 'Ecchi', value: '292' },
{ label: 'Fantasy', value: '5' },
{ label: 'Gender Bender', value: '168' },
{ label: 'Harem', value: '3' },
{ label: 'Historical', value: '330' },
{ label: 'Horror', value: '343' },
{ label: 'Josei', value: '324' },
{ label: 'Martial Arts', value: '14' },
{ label: 'Mature', value: '4' },
{ label: 'Mecha', value: '10' },
{ label: 'Mystery', value: '245' },
{ label: 'Psychoical', value: '486' },
{ label: 'Romance', value: '15' },
{ label: 'School Life', value: '6' },
{ label: 'Sci-fi', value: '11' },
{ label: 'Seinen', value: '18' },
{ label: 'Shoujo', value: '157' },
{ label: 'Shoujo Ai', value: '851' },
{ label: 'Shounen', value: '12' },
{ label: 'Shounen Ai', value: '1692' },
{ label: 'Slice of Life', value: '7' },
{ label: 'Smut', value: '281' },
{ label: 'Sports', value: '1357' },
{ label: 'Supernatural', value: '16' },
{ label: 'Tragedy', value: '132' },
{ label: 'Wuxia', value: '479' },
{ label: 'Xianxia', value: '480' },
{ label: 'Xuanhuan', value: '3954' },
{ label: 'Yaoi', value: '560' },
{ label: 'Yuri', value: '922' },
],
},
language: {
label: 'Language',
value: [],
options: [
{ label: 'Chinese', value: '495' },
{ label: 'Filipino', value: '9181' },
{ label: 'Indonesian', value: '9179' },
{ label: 'Japanese', value: '496' },
{ label: 'Khmer', value: '18657' },
{ label: 'Korean', value: '497' },
{ label: 'Malaysian', value: '9183' },
{ label: 'Thai', value: '9954' },
{ label: 'Vietnamese', value: '9177' },
],
type: FilterTypes.CheckboxGroup,
},
novelType: {
label: 'Novel Type (Not for Popular)',
value: [],
options: [
{ label: 'Light Novel', value: '2443' },
{ label: 'Published Novel', value: '26874' },
{ label: 'Web Novel', value: '2444' },
],
type: FilterTypes.CheckboxGroup,
},
reading_list_operator: {
label: 'Reading List (Include/Exclude) (Not for Popular)',
value: 'include',
options: [
{ label: 'Include', value: 'include' },
{ label: 'Exclude', value: 'exclude' },
],
type: FilterTypes.Picker,
},
reading_lists: {
label: 'Reading Lists (Not for Popular)',
value: [],
options: [{ label: 'All Reading Lists', value: '-1' }],
type: FilterTypes.CheckboxGroup,
},
} satisfies Filters;
}
export default new NovelUpdates();