diff --git a/plugins/english/novelupdates.ts b/plugins/english/novelupdates.ts index a3e3c6d..ce2025e 100644 --- a/plugins/english/novelupdates.ts +++ b/plugins/english/novelupdates.ts @@ -142,8 +142,19 @@ class NovelUpdates implements Plugin.PluginBase { loadedCheerio = parseHTML(text); + const nameReplacements: { [key: string]: string } = { + 'v': 'volume ', + 'c': ' chapter ', + 'part': 'part ', + 'ss': 'SS', + }; + loadedCheerio('li.sp_li_chp').each((i, el) => { - const chapterName = loadedCheerio(el).text().trim(); + let chapterName = loadedCheerio(el).text(); + for (let name in nameReplacements) { + chapterName = chapterName.replace(name, nameReplacements[name]); + } + chapterName = chapterName.replace(/\b\w/g, l => l.toUpperCase()).trim(); const chapterUrl = 'https:' + loadedCheerio(el).find('a').first().next().attr('href'); @@ -182,24 +193,32 @@ class NovelUpdates implements Plugin.PluginBase { case 'anotivereads': chapterTitle = loadedCheerio('#comic-nav-name').first().text()!; chapterContent = loadedCheerio('#spliced-comic').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'asuratls': let titleElementAsura = loadedCheerio('.post-body div b').first(); - chapterTitle = titleElementAsura.first().text(); + chapterTitle = titleElementAsura.text()!; titleElementAsura.remove(); chapterContent = loadedCheerio('.post-body').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'hiraethtranslation': chapterTitle = loadedCheerio('li.active').first().text()!; chapterContent = loadedCheerio('.text-left').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'hostednovel': chapterTitle = loadedCheerio('#chapter-title').first().text()!; chapterContent = loadedCheerio('#chapter-content').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'inoveltranslation': const link_inovel = 'https://api.' + url.slice(8); @@ -212,38 +231,54 @@ class NovelUpdates implements Plugin.PluginBase { '


TL Notes:
' + json_inovel.notes.replace(/\n/g, '
'); } - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'ko-fi': chapterText = loadedCheerio('script:contains("shadowDom.innerHTML")') .html() ?.match(/shadowDom\.innerHTML \+= '( loadedCheerio(tag).remove()); + let titleElementMirilu = loadedCheerio( + '.entry-content p strong', + ).first(); + chapterTitle = titleElementMirilu.text()!; + titleElementMirilu.remove(); + chapterContent = loadedCheerio('.entry-content').html()!; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } + break; case 'novelplex': + bloatClasses = ['.passingthrough_adreminder']; + bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = loadedCheerio('.halChap--jud').first().text()!; chapterContent = loadedCheerio('.halChap--kontenInner ').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'novelworldtranslations': bloatClasses = ['.separator', 'p[dir="ltr"]']; bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = loadedCheerio('.entry-title').first().text()!; - chapterContent = loadedCheerio('.entry-content p span span').html()!; - let chapterContentArray = chapterContent.split('\n').map(paragraph => { - return paragraph.replace(/ /g, '').trim() + '
'; - }); - chapterContent = chapterContentArray.join('').trim(); - chapterText = `

${chapterTitle}


${chapterContent}`; + chapterContent = loadedCheerio('.entry-content p span span') + .html()! + .replace(/ /g, '') + .replace(/\n/g, '
'); + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'raeitranslations': const parts = url.split('/'); const link_raei = `${parts[0]}//api.${parts[2]}/api/chapters/?id=${parts[3]}&num=${parts[4]}`; const json = await fetchApi(link_raei).then(r => r.json()); - chapterTitle = - json.currentChapter.novTitle + - ' | ' + - 'Chapter ' + - json.currentChapter.num; + chapterTitle = 'Chapter ' + json.currentChapter.num; chapterContent = json.currentChapter.head + `


` + @@ -251,23 +286,53 @@ class NovelUpdates implements Plugin.PluginBase { `


Translator's Note:
` + json.currentChapter.note; chapterContent = chapterContent.replace(/\n/g, '
'); - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'rainofsnow': - loadedCheerio('.responsivevoice-button').remove(); - chapterText = loadedCheerio('div.content').html()!; + let displayedDivSnow = loadedCheerio('.bb-item').filter(function () { + return loadedCheerio(this).css('display') === 'block'; + }); + let loadedCheerioSnow = parseHTML(displayedDivSnow.html()!); + bloatClasses = [ + '.responsivevoice-button', + '.zoomdesc-cont p img', + '.zoomdesc-cont p noscript', + ]; + bloatClasses.map(tag => loadedCheerioSnow(tag).remove()); + chapterContent = loadedCheerioSnow('.zoomdesc-cont').html()!; + let titleElementSnow = loadedCheerioSnow('.scroller h2').first(); + if (titleElementSnow.length) { + chapterTitle = titleElementSnow.text()!; + titleElementSnow.remove(); + chapterContent = loadedCheerioSnow('.zoomdesc-cont').html()!; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } + } else if (chapterContent) { + chapterText = chapterContent; + } break; case 'sacredtexttranslations': - bloatClasses = ['.entry-content blockquote', '.entry-content div']; + bloatClasses = [ + '.entry-content blockquote', + '.entry-content div', + '.reaction-buttons', + ]; bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = loadedCheerio('.entry-title').first().text()!; chapterContent = loadedCheerio('.entry-content').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'scribblehub': chapterTitle = loadedCheerio('.chapter-title').first().text()!; chapterContent = loadedCheerio('div.chp_raw').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'stabbingwithasyringe': /** @@ -277,31 +342,37 @@ class NovelUpdates implements Plugin.PluginBase { const resultSyringe = await fetchApi(linkSyringe); const bodySyringe = await resultSyringe.text(); const loadedCheerioSyringe = parseHTML(bodySyringe); - bloatClasses = ['.wp-block-buttons', '#jp-post-flair']; + bloatClasses = ['.wp-block-buttons', '#jp-post-flair', '.wpcnt']; bloatClasses.map(tag => loadedCheerioSyringe(tag).remove()); chapterContent = loadedCheerioSyringe('.entry-content').html()!; let titleElementSyringe = loadedCheerioSyringe('.entry-content h3').first(); if (titleElementSyringe.length) { - chapterTitle = titleElementSyringe.first().text(); + chapterTitle = titleElementSyringe.text(); titleElementSyringe.remove(); chapterContent = loadedCheerioSyringe('.entry-content').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; - } else { + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } + } else if (chapterContent) { chapterText = chapterContent; } break; case 'tinytranslation': bloatClasses = [ + '.content noscript', '.google_translate_element', '.navigate', '.post-views', + 'br', ]; bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = loadedCheerio('.title-content').first().text()!; loadedCheerio('.title-content').first().remove(); chapterContent = loadedCheerio('.content').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}

${chapterContent}`; + } break; case 'tumblr': chapterText = loadedCheerio('.post').html()!; @@ -309,7 +380,9 @@ class NovelUpdates implements Plugin.PluginBase { case 'wattpad': chapterTitle = loadedCheerio('.h2').first().text()!; chapterContent = loadedCheerio('.part-content pre').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'webnovel': chapterTitle = loadedCheerio('.cha-tit .pr .dib').first().text()!; @@ -317,14 +390,35 @@ class NovelUpdates implements Plugin.PluginBase { if (!chapterContent) { chapterContent = loadedCheerio('._content').html()!; } - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; case 'wuxiaworld': bloatClasses = ['.MuiLink-root']; bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = loadedCheerio('h4 span').first().text()!; chapterContent = loadedCheerio('.chapter-content').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } + break; + case 'zetrotranslation': + bloatClasses = ['hr', 'p:contains("\u00a0")']; + bloatClasses.map(tag => loadedCheerio(tag).remove()); + chapterContent = loadedCheerio('.text-left').html()!; + let titleElementZetro = loadedCheerio('.text-left h2').first(); + if (titleElementZetro.length) { + chapterTitle = titleElementZetro.text()!; + titleElementZetro.remove(); + chapterContent = loadedCheerio('.text-left').html()!; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } + } else if (chapterContent) { + chapterTitle = loadedCheerio('.active').first().text()!; + chapterText = `

${chapterTitle}



${chapterContent}`; + } break; } return chapterText; @@ -341,28 +435,26 @@ class NovelUpdates implements Plugin.PluginBase { const url = result.url.toLowerCase(); const domain = url.split('/')[2].split('.'); - // console.log(result.url); - - // console.log('Redirected URL: ', result.chapterUrl); - const loadedCheerio = parseHTML(body); + /** - * Generators are last + * Detect if the site is a Blogspot site */ let isBlogspotStr = loadedCheerio( 'meta[name="google-adsense-platform-domain"]', ).attr('content'); - let isBlogspot = false; if (isBlogspotStr) { isBlogspot = isBlogspotStr.toLowerCase().includes('blogspot'); } + /** + * Detect if the site is a WordPress site + */ let isWordPressStr = - loadedCheerio('#dcl_comments-js-extra').html()! || + loadedCheerio('#dcl_comments-js-extra').html() || loadedCheerio('meta[name="generator"]').attr('content') || - loadedCheerio('footer').text(); - + loadedCheerio('footer').text()!; let isWordPress = false; if (isWordPressStr) { isWordPress = @@ -371,55 +463,66 @@ class NovelUpdates implements Plugin.PluginBase { loadedCheerio('.powered-by').text().toLowerCase().includes('wordpress'); } + /** + * In case sites are not detected correctly + */ + const manualWordPress = ['genesistls']; + if (!isWordPress && domain.find(wp => manualWordPress.includes(wp))) { + isWordPress = true; + } + + /** + * Sites that are WordPress or Blogspot but have different structure + */ const outliers = [ 'anotivereads', 'asuratls', + 'mirilu', 'novelworldtranslations', 'sacredtexttranslations', 'stabbingwithasyringe', 'tinytranslation', + 'zetrotranslation', ]; if (domain.find(d => outliers.includes(d))) { isWordPress = false; isBlogspot = false; } + /** - * Blogspot Novels: - * - AssedTL + * Blogspot sites: + * - ¼-Assed * - AsuraTls (Outlier) * - Novel World Translations (Outlier) - * - SacredText Translation (Outlier) + * - SacredText TL (Outlier) * - * WordPress Novels: - * - A Novel Reader Attempts Translating - * - Anomalously Creative (Outlier) + * WordPress sites: + * - Anomlaously Creative (Outlier) * - Arcane Translations * - Blossom Translation - * - Dumah's Translations - * - ElloTL - * - Gem Novels Translations - * - Genesis Translations + * - Dumahs Translations + * - ElloMTL + * - Gem Novels + * - Genesis Translations (Manually added) * - Goblinslate * - Hel Scans - * - Ippo Translations + * - ippotranslations * - JATranslations * - Light Novels Translations + * - Mirilu - Novel Reader Attempts Translating (Outlier) * - Neosekai Translations * - Shanghai Fantasy - * - Soafp Translations + * - Soafp * - Stabbing with a Syringe (Outlier) - * - Stone Scape - * - Tiny Translation (Outlier) + * - StoneScape + * - TinyTL (Outlier) * - Wonder Novels * - Yong Library - * - Zetro Translation + * - Zetro Translation (Outlier) */ if (!isWordPress && !isBlogspot) { chapterText = await this.getChapterBody(loadedCheerio, domain, url); } else if (isBlogspot) { - /** - * Generators are last - */ bloatClasses = ['.button-container', '.separator']; bloatClasses.map(tag => loadedCheerio(tag).remove()); chapterTitle = @@ -428,13 +531,14 @@ class NovelUpdates implements Plugin.PluginBase { chapterContent = loadedCheerio('.entry-content').html() || loadedCheerio('.post-body').html()!; - chapterText = `

${chapterTitle}


${chapterContent}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; + } } else if (isWordPress) { bloatClasses = [ '.ad', '.author-avatar', '.chapter-warning', - '.entry-content .has-text-align-center', '.entry-meta', '.ezoic-ad', '.mb-center', @@ -462,6 +566,9 @@ class NovelUpdates implements Plugin.PluginBase { loadedCheerio('.active').first().text() || loadedCheerio('head title').first().text()!; let chapterSubtitle = loadedCheerio('.cat-series').first().text() || ''; + if (chapterSubtitle) { + chapterTitle = chapterSubtitle; + } chapterContent = loadedCheerio('.rdminimal').html() || loadedCheerio('.entry-content').html() || @@ -477,10 +584,9 @@ class NovelUpdates implements Plugin.PluginBase { loadedCheerio('.td-page-content').html() || loadedCheerio('#content').html() || loadedCheerio('article.post').html()!; - if (chapterSubtitle) { - chapterTitle = `${chapterTitle} | ${chapterSubtitle}`; + if (chapterTitle && chapterContent) { + chapterText = `

${chapterTitle}



${chapterContent}`; } - chapterText = `

${chapterTitle}


${chapterContent}`; } if (!chapterText) { @@ -509,11 +615,17 @@ class NovelUpdates implements Plugin.PluginBase { searchTerm: string, page: number, ): Promise { - const url = - this.site + - '?s=' + - searchTerm.replace(/\s+/g, '+') + - '&post_type=seriesplans'; + /** + * 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 + '?s=' + searchTerm + '&post_type=seriesplans'; const result = await fetchApi(url); const body = await result.text(); const loadedCheerio = parseHTML(body);