feat: Maintain Novel Updates Plugin With New Sources (#1952)
* Add GreenzTL * fix * fix * Version update * fix * add debug * Improve Wordpress and Blogspot detection * further updates * Added Dreamy Translations * fix * fix * fix * fix * test * Add Novels Hub * Revert versions
This commit is contained in:
+245
-172
@@ -6,7 +6,7 @@ import { Plugin } from '@/types/plugin';
|
|||||||
class NovelUpdates implements Plugin.PluginBase {
|
class NovelUpdates implements Plugin.PluginBase {
|
||||||
id = 'novelupdates';
|
id = 'novelupdates';
|
||||||
name = 'Novel Updates';
|
name = 'Novel Updates';
|
||||||
version = '0.9.4';
|
version = '0.9.5';
|
||||||
icon = 'src/en/novelupdates/icon.png';
|
icon = 'src/en/novelupdates/icon.png';
|
||||||
customCSS = 'src/en/novelupdates/customCSS.css';
|
customCSS = 'src/en/novelupdates/customCSS.css';
|
||||||
site = 'https://www.novelupdates.com/';
|
site = 'https://www.novelupdates.com/';
|
||||||
@@ -196,43 +196,6 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
||||||
case 'anotivereads': {
|
|
||||||
chapterTitle = loadedCheerio('#comic-nav-name').first().text();
|
|
||||||
chapterContent = loadedCheerio('#spliced-comic').html()!;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
|
||||||
case 'arcanetranslations': {
|
|
||||||
bloatElements = ['.bottomnav'];
|
|
||||||
bloatElements.forEach(tag => loadedCheerio(tag).remove());
|
|
||||||
chapterTitle = loadedCheerio('.epwrapper .cat-series').first().text();
|
|
||||||
loadedCheerio('.entry-content div, .entry-content span').each(
|
|
||||||
(_, element) => {
|
|
||||||
const el = loadedCheerio(element);
|
|
||||||
const style = el.attr('style');
|
|
||||||
if (!style) return; // Skip elements without inline styles
|
|
||||||
if (/border:.*#00219b/.test(style)) {
|
|
||||||
el.removeAttr('style').addClass('arcane_box_blue'); // Blue box
|
|
||||||
} else if (/border:.*white/.test(style)) {
|
|
||||||
el.removeAttr('style').addClass('arcane_box_white'); // White box
|
|
||||||
} else if (
|
|
||||||
style.includes('text-transform: uppercase') &&
|
|
||||||
/text-shadow:.*blue/.test(style)
|
|
||||||
) {
|
|
||||||
el.removeAttr('style').addClass('arcane_title_blue'); // Blue title
|
|
||||||
} else if (/text-shadow:.*blue/.test(style)) {
|
|
||||||
el.removeAttr('style').addClass('arcane_text_blue'); // Blue text
|
|
||||||
} else if (/text-shadow:.*lightyellow/.test(style)) {
|
|
||||||
el.removeAttr('style').addClass('arcane_text_lightyellow'); // Lightyellow text
|
|
||||||
} else if (/color:.*#ff00ff/.test(style)) {
|
|
||||||
el.removeAttr('style').addClass('arcane_text_pink'); // Pink text
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
chapterContent = loadedCheerio('.entry-content').html()!;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
|
||||||
case 'asuratls': {
|
case 'asuratls': {
|
||||||
const titleElement = loadedCheerio('.post-body div b').first();
|
const titleElement = loadedCheerio('.post-body div b').first();
|
||||||
chapterTitle = titleElement.text();
|
chapterTitle = titleElement.text();
|
||||||
@@ -348,6 +311,11 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
chapterContent = loadedCheerio('.chapter__content').html()!;
|
chapterContent = loadedCheerio('.chapter__content').html()!;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Last edited in 0.9.5 by Batorian - 26/12/2025
|
||||||
|
case 'dreamy-translations': {
|
||||||
|
chapterTitle = loadedCheerio('h1 > span').first().text();
|
||||||
|
chapterContent = loadedCheerio('.chapter-content').html()!;
|
||||||
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
||||||
case 'fictionread': {
|
case 'fictionread': {
|
||||||
bloatElements = [
|
bloatElements = [
|
||||||
@@ -411,22 +379,24 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.5 by Batorian - 26/12/2025
|
||||||
case 'helscans': {
|
case 'greenztl': {
|
||||||
chapterTitle = loadedCheerio('.entry-title-main').first().text();
|
const chapterSlug = chapterPath.split('/').pop();
|
||||||
const chapterString_helscans =
|
const apiUrl = `https://greenztl.com/api/chapters/slug/${chapterSlug}`;
|
||||||
'Chapter ' + chapterTitle.split('Chapter')[1].trim();
|
|
||||||
loadedCheerio('#readerarea.rdminimal')
|
try {
|
||||||
.children()
|
const response = await fetchApi(apiUrl);
|
||||||
.each((_, el) => {
|
const json = await response.json();
|
||||||
const elementText = loadedCheerio(el).text();
|
|
||||||
if (elementText.includes(chapterString_helscans)) {
|
const chapterName = json.data.name;
|
||||||
chapterTitle = elementText;
|
const chapterNumber = json.data.chapterNumber;
|
||||||
loadedCheerio(el).remove();
|
const chapterCheerio = parseHTML(json.data.content);
|
||||||
return false;
|
|
||||||
}
|
chapterTitle = `Chapter ${chapterNumber} - ${chapterName}`;
|
||||||
});
|
chapterContent = chapterCheerio.html()!;
|
||||||
chapterContent = loadedCheerio('#readerarea.rdminimal').html()!;
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to parse GreenzTL chapter: ${error}`);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
||||||
@@ -441,7 +411,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
chapterContent = loadedCheerio('#chapter-content').html()!;
|
chapterContent = loadedCheerio('#chapter-content').html()!;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.5 by Batorian - 26/12/2025
|
||||||
case 'infinitenoveltranslations': {
|
case 'infinitenoveltranslations': {
|
||||||
// Get the chapter link from the main page
|
// Get the chapter link from the main page
|
||||||
const url = loadedCheerio('article > p > a').first().attr('href')!;
|
const url = loadedCheerio('article > p > a').first().attr('href')!;
|
||||||
@@ -450,8 +420,8 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
const body = await response.text();
|
const body = await response.text();
|
||||||
loadedCheerio = parseHTML(body);
|
loadedCheerio = parseHTML(body);
|
||||||
}
|
}
|
||||||
chapterContent = loadedCheerio('.hentry').html()!;
|
chapterContent = loadedCheerio('.entry-content').html()!;
|
||||||
chapterTitle = loadedCheerio('.page-entry-title').text();
|
chapterTitle = loadedCheerio('.entry-title').text();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
||||||
@@ -537,6 +507,80 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
chapterContent = loadedCheerio('.halChap--kontenInner ').html()!;
|
chapterContent = loadedCheerio('.halChap--kontenInner ').html()!;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'novelshub': {
|
||||||
|
const segments = chapterPath.split('/');
|
||||||
|
const novelSlug = segments[segments.length - 2];
|
||||||
|
const chapterSlug = segments[segments.length - 1];
|
||||||
|
const apiUrl = `https://api.novelshub.org/api/chapter?mangaslug=${novelSlug}&chapterslug=${chapterSlug}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetchApi(apiUrl);
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
|
const chapterNumber = json.chapter.number;
|
||||||
|
const chapterCheerio = parseHTML(json.chapter.content);
|
||||||
|
|
||||||
|
chapterTitle = `Chapter ${chapterNumber}`;
|
||||||
|
chapterCheerio('div').each((_, element) => {
|
||||||
|
const el = chapterCheerio(element);
|
||||||
|
const style = el.attr('style');
|
||||||
|
if (!style) return; // Skip elements without inline styles
|
||||||
|
// Orange box
|
||||||
|
if (/border:.*#ff6b00/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box_orange');
|
||||||
|
// Orange box title
|
||||||
|
} else if (
|
||||||
|
/color:.*#ff6b00.*text-transform:.*uppercase/.test(style)
|
||||||
|
) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box-title_orange');
|
||||||
|
// Orange box text
|
||||||
|
} else if (/color:.*white.*border-top:.*#ff6b00/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box-text_orange');
|
||||||
|
// Green box
|
||||||
|
} else if (/border:.*#00ff88/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box_green');
|
||||||
|
// Green box title
|
||||||
|
} else if (
|
||||||
|
/color:.*#00ff88.*text-transform:.*uppercase/.test(style)
|
||||||
|
) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box-title_green');
|
||||||
|
// Green comment
|
||||||
|
} else if (/border-left:.*#00ff88/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_comment_green');
|
||||||
|
// Blue box
|
||||||
|
} else if (/border:.*#0066ff/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box_blue');
|
||||||
|
// Blue box title
|
||||||
|
} else if (
|
||||||
|
/color:.*#0099ff.*text-transform:.*uppercase/.test(style)
|
||||||
|
) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box-title_blue');
|
||||||
|
// Blue box text
|
||||||
|
} else if (/color:.*#d0d0d0/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_box-text_blue');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chapterCheerio('span').each((_, element) => {
|
||||||
|
const el = chapterCheerio(element);
|
||||||
|
const style = el.attr('style');
|
||||||
|
if (!style) return; // Skip elements without inline styles
|
||||||
|
// Red text
|
||||||
|
if (/color:.*#ff6b6b/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_text_red');
|
||||||
|
// Blue text
|
||||||
|
} else if (/color:.*#4d9fff/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_text_blue');
|
||||||
|
// Purple text
|
||||||
|
} else if (/color:.*#a78bfa/.test(style)) {
|
||||||
|
el.removeAttr('style').addClass('novels-hub_text_purple');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
chapterContent = chapterCheerio.html()!;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to parse GreenzTL chapter: ${error}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
// Last edited in 0.9.0 by Batorian - 19/03/2025
|
||||||
case 'novelworldtranslations': {
|
case 'novelworldtranslations': {
|
||||||
bloatElements = ['.separator img'];
|
bloatElements = ['.separator img'];
|
||||||
@@ -779,19 +823,6 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
chapterText = await fetchApi(json).then(r => r.text());
|
chapterText = await fetchApi(json).then(r => r.text());
|
||||||
break;
|
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 (!chapterText) {
|
||||||
if (chapterTitle) {
|
if (chapterTitle) {
|
||||||
@@ -833,38 +864,70 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect platforms
|
// Helper to safely check if any element matches a regex or string
|
||||||
let isBlogspot = ['blogspot', 'blogger'].some(keyword =>
|
const matches = (selector: string, attr: string | null, regex: RegExp) => {
|
||||||
[
|
let found = false;
|
||||||
loadedCheerio('meta[name="google-adsense-platform-domain"]').attr(
|
loadedCheerio(selector).each((_, el) => {
|
||||||
'content',
|
const val = attr
|
||||||
),
|
? loadedCheerio(el).attr(attr)
|
||||||
loadedCheerio('meta[name="generator"]').attr('content'),
|
: loadedCheerio(el).html() || loadedCheerio(el).text();
|
||||||
].some(meta => meta?.toLowerCase().includes(keyword)),
|
if (val && regex.test(val.toLowerCase())) {
|
||||||
);
|
found = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
let isWordPress = ['wordpress', 'site kit by google'].some(keyword =>
|
// --- WordPress Detection ---
|
||||||
[
|
let isWordPress = [
|
||||||
loadedCheerio('#dcl_comments-js-extra').html(),
|
// 1. Meta Generator
|
||||||
loadedCheerio('meta[name="generator"]').attr('content'),
|
matches('meta[name="generator"]', 'content', /wordpress|site kit/i),
|
||||||
loadedCheerio('.powered-by').text(),
|
// 2. Resource Paths (The most reliable way)
|
||||||
loadedCheerio('footer').text(),
|
matches('link, script, img', 'src', /\/wp-content\/|\/wp-includes\//i),
|
||||||
].some(meta => meta?.toLowerCase().includes(keyword)),
|
matches('link', 'href', /\/wp-content\/|\/wp-includes\//i),
|
||||||
);
|
// 3. Header Links (REST API, RSD, etc.)
|
||||||
|
matches('link[rel="https://api.w.org/"]', 'href', /.*/),
|
||||||
|
matches('link[rel="EditURI"]', 'href', /xmlrpc\.php/i),
|
||||||
|
// 4. Common Body Classes
|
||||||
|
matches('body', 'class', /wp-admin|wp-custom-logo|logged-in/i),
|
||||||
|
// 5. Scripts containing WP globals
|
||||||
|
matches('script', null, /wp-embed|wp-emoji|wp-block/i),
|
||||||
|
].some(Boolean);
|
||||||
|
|
||||||
// Manually set WordPress flag for known sites
|
// --- Blogspot / Blogger Detection ---
|
||||||
const manualWordPress = ['etherreads', 'greenztl2', 'soafp'];
|
let isBlogspot = [
|
||||||
if (!isWordPress && domainParts.some(wp => manualWordPress.includes(wp))) {
|
// 1. Meta Tags
|
||||||
isWordPress = true;
|
matches('meta[name="generator"]', 'content', /blogger/i),
|
||||||
}
|
matches(
|
||||||
|
'meta[name="google-adsense-platform-domain"]',
|
||||||
|
'content',
|
||||||
|
/blogspot/i,
|
||||||
|
),
|
||||||
|
// 2. Feed links
|
||||||
|
matches(
|
||||||
|
'link[rel="alternate"]',
|
||||||
|
'href',
|
||||||
|
/blogger\.com\/feeds|blogspot\.com\/feeds/i,
|
||||||
|
),
|
||||||
|
// 3. Specific Blogger CSS/Template markers
|
||||||
|
matches(
|
||||||
|
'link',
|
||||||
|
'href',
|
||||||
|
/www\.blogger\.com\/static|www\.blogger\.com\/dyn-css/i,
|
||||||
|
),
|
||||||
|
// 4. Blogger Script Widget Manager
|
||||||
|
matches(
|
||||||
|
'script',
|
||||||
|
null,
|
||||||
|
/_WidgetManager\._Init|_WidgetManager\._RegisterWidget/i,
|
||||||
|
),
|
||||||
|
].some(Boolean);
|
||||||
|
|
||||||
// Handle outlier sites
|
// Handle outlier sites
|
||||||
const outliers = [
|
const outliers = [
|
||||||
'anotivereads',
|
|
||||||
'arcanetranslations',
|
|
||||||
'asuratls',
|
'asuratls',
|
||||||
'fictionread',
|
'fictionread',
|
||||||
'helscans',
|
|
||||||
'hiraethtranslation',
|
'hiraethtranslation',
|
||||||
'infinitenoveltranslations',
|
'infinitenoveltranslations',
|
||||||
'machineslicedbread',
|
'machineslicedbread',
|
||||||
@@ -874,14 +937,13 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
'stabbingwithasyringe',
|
'stabbingwithasyringe',
|
||||||
'tinytranslation',
|
'tinytranslation',
|
||||||
'vampiramtl',
|
'vampiramtl',
|
||||||
'zetrotranslation',
|
|
||||||
];
|
];
|
||||||
if (domainParts.some(d => outliers.includes(d))) {
|
if (domainParts.some(d => outliers.includes(d))) {
|
||||||
isWordPress = false;
|
isWordPress = false;
|
||||||
isBlogspot = false;
|
isBlogspot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last edited in 0.9.2 - 08/09/2025
|
// Last edited in 0.9.5 - 26/12/2025
|
||||||
/**
|
/**
|
||||||
* Blogspot sites:
|
* Blogspot sites:
|
||||||
* - ¼-Assed
|
* - ¼-Assed
|
||||||
@@ -892,18 +954,13 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
* - Toasteful
|
* - Toasteful
|
||||||
*
|
*
|
||||||
* WordPress sites:
|
* WordPress sites:
|
||||||
* - Anomlaously Creative (Outlier)
|
|
||||||
* - Arcane Translations (Outlier)
|
|
||||||
* - Blossom Translation
|
|
||||||
* - Dumah's Translations
|
* - Dumah's Translations
|
||||||
* - ElloMTL
|
|
||||||
* - Ether Reads
|
* - Ether Reads
|
||||||
* - Femme Fables
|
* - Femme Fables
|
||||||
* - Gadgetized Panda Translation
|
* - Gadgetized Panda Translation
|
||||||
* - Gem Novels
|
|
||||||
* - Goblinslate
|
* - Goblinslate
|
||||||
* - Hel Scans (Outlier)
|
|
||||||
* - Hiraeth Translation (Outlier)
|
* - Hiraeth Translation (Outlier)
|
||||||
|
* - Infinite Novel Translations (Outlier)
|
||||||
* - ippotranslations
|
* - ippotranslations
|
||||||
* - JATranslations
|
* - JATranslations
|
||||||
* - Light Novels Translations
|
* - Light Novels Translations
|
||||||
@@ -912,98 +969,114 @@ class NovelUpdates implements Plugin.PluginBase {
|
|||||||
* - Neosekai Translations
|
* - Neosekai Translations
|
||||||
* - Noice Translations
|
* - Noice Translations
|
||||||
* - Shanghai Fantasy
|
* - Shanghai Fantasy
|
||||||
* - Soafp (Manually added)
|
* - Sleepy Translations
|
||||||
|
* - Soafp
|
||||||
* - Stabbing with a Syringe (Outlier)
|
* - Stabbing with a Syringe (Outlier)
|
||||||
* - StoneScape
|
* - StoneScape
|
||||||
* - TinyTL (Outlier)
|
* - TinyTL (Outlier)
|
||||||
* - VampiraMTL (Outlier)
|
* - VampiraMTL (Outlier)
|
||||||
* - Wonder Novels
|
* - Wonder Novels
|
||||||
* - Yong Library
|
* - Yong Library
|
||||||
* - Zetro Translation (Outlier)
|
* - Zetro Translation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Fetch chapter content based on detected platform
|
// Define Platform Configurations
|
||||||
|
const PLATFORM_CONFIG = {
|
||||||
|
wordpress: {
|
||||||
|
bloat: [
|
||||||
|
'.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-dark-mode-switcher',
|
||||||
|
'.wp-next-post-navi',
|
||||||
|
'#hpk',
|
||||||
|
'#jp-post-flair',
|
||||||
|
'#textbox',
|
||||||
|
],
|
||||||
|
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',
|
||||||
|
],
|
||||||
|
content: [
|
||||||
|
'.chapter__content',
|
||||||
|
'.entry-content',
|
||||||
|
'.text_story',
|
||||||
|
'.post-content',
|
||||||
|
'.contenta',
|
||||||
|
'.single_post',
|
||||||
|
'.main-content',
|
||||||
|
'.reader-content',
|
||||||
|
'#content',
|
||||||
|
'#the-content',
|
||||||
|
'article.post',
|
||||||
|
'.chp_raw',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
blogspot: {
|
||||||
|
bloat: ['.button-container', '.ChapterNav', '.ch-bottom', '.separator'],
|
||||||
|
title: ['.entry-title', '.post-title', 'head title'],
|
||||||
|
content: ['.content-post', '.entry-content', '.post-body'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extraction Logic
|
||||||
if (!isWordPress && !isBlogspot) {
|
if (!isWordPress && !isBlogspot) {
|
||||||
chapterText = await this.getChapterBody(loadedCheerio, domainParts, url);
|
chapterText = await this.getChapterBody(loadedCheerio, domainParts, url);
|
||||||
} else {
|
} else {
|
||||||
const bloatElements = isBlogspot
|
const config = isWordPress
|
||||||
? ['.button-container', '.ChapterNav', '.ch-bottom', '.separator']
|
? PLATFORM_CONFIG.wordpress
|
||||||
: [
|
: PLATFORM_CONFIG.blogspot;
|
||||||
'.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());
|
// Remove platform-specific bloat
|
||||||
|
config.bloat.forEach(tag => loadedCheerio(tag).remove());
|
||||||
|
|
||||||
// Extract title
|
// Extract Title (Simplified find)
|
||||||
const titleSelectors = isBlogspot
|
let chapterTitle = config.title
|
||||||
? ['.entry-title', '.post-title', 'head title']
|
.map(sel => loadedCheerio(sel).first().text().trim())
|
||||||
: [
|
.find(text => text.length > 0);
|
||||||
'.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)
|
// Handle Subtitles
|
||||||
const chapterSubtitle =
|
const chapterSubtitle =
|
||||||
loadedCheerio('.cat-series').first().text() ||
|
loadedCheerio('.cat-series').first().text() ||
|
||||||
loadedCheerio('h1.leading-none ~ span').first().text();
|
loadedCheerio('h1.leading-none ~ span').first().text() ||
|
||||||
|
loadedCheerio('.breadcrumb .active').first().text();
|
||||||
|
|
||||||
if (chapterSubtitle) chapterTitle = chapterSubtitle;
|
if (chapterSubtitle) chapterTitle = chapterSubtitle;
|
||||||
|
|
||||||
// Extract content
|
// Extract Content (Scoped search)
|
||||||
const contentSelectors = isBlogspot
|
const chapterContent = config.content
|
||||||
? ['.content-post', '.entry-content', '.post-body']
|
.map(sel => {
|
||||||
: [
|
const el = loadedCheerio(sel).first();
|
||||||
'.chapter__content',
|
// Ensure we don't pick up empty containers
|
||||||
'.entry-content',
|
return el.text().trim().length > 50 ? el.html() : null;
|
||||||
'.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);
|
.find(html => html);
|
||||||
|
|
||||||
|
// Construct Final Text
|
||||||
if (chapterTitle && chapterContent) {
|
if (chapterTitle && chapterContent) {
|
||||||
chapterText = `<h2>${chapterTitle}</h2><hr><br>${chapterContent}`;
|
chapterText = `<h2>${chapterTitle}</h2><hr><br>${chapterContent}`;
|
||||||
} else {
|
} else {
|
||||||
chapterText = chapterContent;
|
chapterText = chapterContent || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,3 @@
|
|||||||
/**
|
|
||||||
* Novel Updates -> Arcane Translations
|
|
||||||
* https://www.novelupdates.com/group/arcane-translations/
|
|
||||||
* Necessary to display chapterContent correctly
|
|
||||||
*/
|
|
||||||
|
|
||||||
.arcane_box_blue {
|
|
||||||
text-align: center;
|
|
||||||
border: 2px solid #00219b;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 0 10px #00219b;
|
|
||||||
background-color: black;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arcane_box_white {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
border: 2px solid white;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: 0 0 10px white;
|
|
||||||
background-color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arcane_title_blue {
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
text-shadow: 0 0 10px blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arcane_text_blue {
|
|
||||||
color: white;
|
|
||||||
border-top: 2px solid white;
|
|
||||||
padding-top: 10px;
|
|
||||||
text-shadow: 0 0 8px blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arcane_text_lightyellow {
|
|
||||||
color: white;
|
|
||||||
text-shadow: 0 0 8px lightyellow;
|
|
||||||
font-family: 'Amita', cursive;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arcane_text_pink {
|
|
||||||
color: #ff00ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Novel Updates -> Daoist Quest
|
* Novel Updates -> Daoist Quest
|
||||||
* https://www.novelupdates.com/group/daoist-quest/
|
* https://www.novelupdates.com/group/daoist-quest/
|
||||||
@@ -436,6 +386,84 @@ div.blue-text {
|
|||||||
flex-direction:column
|
flex-direction:column
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Novel Updates -> Novels Hub
|
||||||
|
* https://www.novelupdates.com/group/novelshub/
|
||||||
|
* Necessary to display chapterContent correctly
|
||||||
|
*/
|
||||||
|
.novels-hub_box_orange {
|
||||||
|
text-align: center;
|
||||||
|
border: 2px solid #ff6b00;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 15px rgba(255, 107, 0, 0.4);
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.novels-hub_box-title_orange {
|
||||||
|
color: #ff6b00;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-shadow: 0 0 10px rgba(255, 107, 0, 0.6);
|
||||||
|
}
|
||||||
|
.novels-hub_box-text_orange {
|
||||||
|
color: white;
|
||||||
|
line-height: 1.6;
|
||||||
|
border-top: 1px solid #ff6b00;
|
||||||
|
padding-top: 15px;
|
||||||
|
text-shadow: 0 0 5px rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
.novels-hub_box_green {
|
||||||
|
background: #0d0d0d;
|
||||||
|
border: 2px solid #00ff88;
|
||||||
|
padding: 15px 20px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 255, 136, 0.3);
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.novels-hub_box-title_green {
|
||||||
|
color: #00ff88;
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
text-shadow: 0 0 8px rgba(0, 255, 136, 0.5);
|
||||||
|
}
|
||||||
|
.novels-hub_comment_green {
|
||||||
|
background: linear-gradient(135deg, #1a1a1a 0%, #0f0f0f 100%);
|
||||||
|
border-left: 4px solid #00ff88;
|
||||||
|
padding: 15px 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
.novels-hub_box_blue {
|
||||||
|
background: rgba(0, 33, 155, 0.15);
|
||||||
|
border: 1px solid #0066ff;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
box-shadow: inset 0 0 10px rgba(0, 102, 255, 0.1);
|
||||||
|
}
|
||||||
|
.novels-hub_box-title_blue {
|
||||||
|
color: #0099ff;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
}
|
||||||
|
.novels-hub_box-text_blue {
|
||||||
|
color: #d0d0d0;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.novels-hub_text_red {
|
||||||
|
color: #ff6b6b;
|
||||||
|
}
|
||||||
|
.novels-hub_text_blue {
|
||||||
|
color: #4d9fff;
|
||||||
|
}
|
||||||
|
.novels-hub_text_purple {
|
||||||
|
color: #a78bfa;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Novel Updates -> Raei Translations
|
* Novel Updates -> Raei Translations
|
||||||
* https://www.novelupdates.com/group/raei-translations/
|
* https://www.novelupdates.com/group/raei-translations/
|
||||||
|
|||||||
Reference in New Issue
Block a user