Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions plugins/indonesian/sakuranovel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@ import { fetchApi } from '@libs/fetch';
import { Plugin } from '@/types/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs';

// `.tldariinggrissendiribrojangancopy` is the site's own obfuscated content wrapper class, not a typo — keep it in sync with the live markup.
const CHAPTER_CONTENT_SELECTORS = [
'.tldariinggrissendiribrojangancopy .entry-content',
'.entry-content',
];

// Promo paragraph the site injects into chapter bodies; rewordings only need updating here.
const PROMO_TEXT = 'Baca novel lain di sakuranovel';

class SakuraNovel implements Plugin.PluginBase {
id = 'sakura.id';
name = 'SakuraNovel';
icon = 'src/id/sakuranovel/icon.png';
site = 'https://sakuranovel.id/';
version = '1.0.1';
version = '1.0.2';

parseNovels(loadedCheerio: CheerioAPI) {
const novels: Plugin.NovelItem[] = [];
Expand Down Expand Up @@ -137,14 +146,31 @@ class SakuraNovel implements Plugin.PluginBase {

const loadedCheerio = parseHTML(body);

const divi = loadedCheerio("div:contains('Daftar Isi') +")
.find('div:first')
.attr('class');
loadedCheerio(`.${divi}`).remove();
const chapterText =
loadedCheerio("div:contains('Daftar Isi') +").html() || '';
// Tier 1: themed content container — the obfuscated parent class marks the real chapter body when the site serves its full theme markup.
for (const selector of CHAPTER_CONTENT_SELECTORS) {
const content = loadedCheerio(selector).first();
if (!content.length) continue;
content.find(`p:contains('${PROMO_TEXT}')`).remove();
const chapterText = (content.html() || '').trim();
if (chapterText) return chapterText;
}

// Tier 2: markdown-rendered chapters expose one paragraph per element.
const paragraphs = loadedCheerio('p.ds-markdown-paragraph')
.map((i, el) => {
const para = loadedCheerio(el);
if (para.text().includes(PROMO_TEXT)) return '';
return para.toString();
})
.get()
.join('');
if (paragraphs.trim()) return paragraphs;

return chapterText;
// Tier 3 (last resort): the legacy layout locates the body as the sibling after the 'Daftar Isi' div — fragile by construction since :contains matches every ancestor, so this stays last and scoped to the container only.
const legacy = loadedCheerio("div:contains('Daftar Isi') +").first();
const legacyInner = legacy.find('div:first').attr('class');
if (legacyInner) legacy.find(`.${legacyInner.split(' ')[0]}`).remove();
return legacy.html() || '';
}

async searchNovels(
Expand Down
Loading