From fe4c1ea1452923de598fdde4bbe4afea7c43b697 Mon Sep 17 00:00:00 2001 From: 7ui77 <99854073+7ui77@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:37:58 +0000 Subject: [PATCH 1/2] fix(madara): handle volume-grouped chapter lists and bump foxaholic to v2.2.2 --- plugins/multisrc/madara/sources.json | 2 +- plugins/multisrc/madara/template.ts | 48 ++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/plugins/multisrc/madara/sources.json b/plugins/multisrc/madara/sources.json index 6e7b38526..7c4dbd323 100644 --- a/plugins/multisrc/madara/sources.json +++ b/plugins/multisrc/madara/sources.json @@ -223,7 +223,7 @@ "options": { "useNewChapterEndpoint": true, "resolveCoverDataUri": true, - "versionIncrements": 1 + "versionIncrements": 2 } }, { diff --git a/plugins/multisrc/madara/template.ts b/plugins/multisrc/madara/template.ts index 466c8c9be..e07a2eb90 100644 --- a/plugins/multisrc/madara/template.ts +++ b/plugins/multisrc/madara/template.ts @@ -442,14 +442,18 @@ export class MadaraPlugin implements Plugin.PluginBase { }).then((res: Response) => res.text()); } - if (html !== '0') { - loadedCheerio = parseHTML(html); + if (html && html !== '0') { + const parsedChapters = parseHTML(html); + if (parsedChapters('.wp-manga-chapter').length > 0) { + loadedCheerio = parsedChapters; + } } - const totalChapters = loadedCheerio('.wp-manga-chapter').length; - loadedCheerio('.wp-manga-chapter').each((chapterIndex, element) => { + const parseChapterElement = ( + element: AnyNode, + ): Plugin.ChapterItem | null => { let chapterName = loadedCheerio(element).find('a').text().trim(); - const locked = element.attribs['class'].includes('premium-block'); + const locked = loadedCheerio(element).hasClass('premium-block'); if (locked) { chapterName = '🔒 ' + chapterName; } @@ -468,16 +472,42 @@ export class MadaraPlugin implements Plugin.PluginBase { const chapterUrl = loadedCheerio(element).find('a').attr('href') || ''; if (chapterUrl && chapterUrl != '#' && !(locked && this.hideLocked)) { - chapters.push({ + return { name: chapterName, path: chapterUrl.replace(/https?:\/\/.*?\//, ''), releaseTime: releaseDate || null, - chapterNumber: totalChapters - chapterIndex, - }); + }; } + return null; + }; + + const volumeElements = loadedCheerio( + 'ul.main > li.has-child, ul.main > li.parent', + ); + if (volumeElements.length > 0) { + volumeElements.each((_, volEl) => { + const volChapters: Plugin.ChapterItem[] = []; + loadedCheerio(volEl) + .find('.wp-manga-chapter') + .each((_, element) => { + const chap = parseChapterElement(element); + if (chap) volChapters.push(chap); + }); + chapters.push(...volChapters.reverse()); + }); + } else { + loadedCheerio('.wp-manga-chapter').each((_, element) => { + const chap = parseChapterElement(element); + if (chap) chapters.push(chap); + }); + chapters.reverse(); + } + + chapters.forEach((chapter, index) => { + chapter.chapterNumber = index + 1; }); - novel.chapters = chapters.reverse(); + novel.chapters = chapters; return novel; } From c2fc56ebd35b5015ef2d62a3137cd6793a7ff8b0 Mon Sep 17 00:00:00 2001 From: 7ui77 <99854073+7ui77@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:55:42 +0000 Subject: [PATCH 2/2] fix(madara): preserve standalone chapters and maintain chapter numbering with hideLocked --- plugins/multisrc/madara/template.ts | 66 +++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/plugins/multisrc/madara/template.ts b/plugins/multisrc/madara/template.ts index e07a2eb90..da3740155 100644 --- a/plugins/multisrc/madara/template.ts +++ b/plugins/multisrc/madara/template.ts @@ -449,9 +449,9 @@ export class MadaraPlugin implements Plugin.PluginBase { } } - const parseChapterElement = ( - element: AnyNode, - ): Plugin.ChapterItem | null => { + type RawChapter = Plugin.ChapterItem & { isLocked: boolean }; + + const parseChapterElement = (element: AnyNode): RawChapter | null => { let chapterName = loadedCheerio(element).find('a').text().trim(); const locked = loadedCheerio(element).hasClass('premium-block'); if (locked) { @@ -471,11 +471,12 @@ export class MadaraPlugin implements Plugin.PluginBase { const chapterUrl = loadedCheerio(element).find('a').attr('href') || ''; - if (chapterUrl && chapterUrl != '#' && !(locked && this.hideLocked)) { + if (chapterUrl && chapterUrl != '#') { return { name: chapterName, path: chapterUrl.replace(/https?:\/\/.*?\//, ''), releaseTime: releaseDate || null, + isLocked: locked, }; } return null; @@ -484,30 +485,67 @@ export class MadaraPlugin implements Plugin.PluginBase { const volumeElements = loadedCheerio( 'ul.main > li.has-child, ul.main > li.parent', ); + const allChapters: RawChapter[] = []; + if (volumeElements.length > 0) { - volumeElements.each((_, volEl) => { - const volChapters: Plugin.ChapterItem[] = []; - loadedCheerio(volEl) - .find('.wp-manga-chapter') - .each((_, element) => { + let standaloneBatch: RawChapter[] = []; + const flushStandalone = () => { + if (standaloneBatch.length > 0) { + allChapters.push(...standaloneBatch.reverse()); + standaloneBatch = []; + } + }; + + loadedCheerio('ul.main > li').each((_, li) => { + const $li = loadedCheerio(li); + if ($li.is('.has-child, .parent')) { + flushStandalone(); + const volChapters: RawChapter[] = []; + $li.find('.wp-manga-chapter').each((_, element) => { const chap = parseChapterElement(element); if (chap) volChapters.push(chap); }); - chapters.push(...volChapters.reverse()); + allChapters.push(...volChapters.reverse()); + } else if ($li.hasClass('wp-manga-chapter')) { + const chap = parseChapterElement(li); + if (chap) standaloneBatch.push(chap); + } else { + $li.find('.wp-manga-chapter').each((_, element) => { + const chap = parseChapterElement(element); + if (chap) standaloneBatch.push(chap); + }); + } }); + flushStandalone(); + + // Ensure any standalone chapters outside ul.main > li are also preserved + const accountedPaths = new Set(allChapters.map(c => c.path)); + const missing: RawChapter[] = []; + loadedCheerio('.wp-manga-chapter').each((_, element) => { + const chap = parseChapterElement(element); + if (chap && !accountedPaths.has(chap.path)) { + missing.push(chap); + } + }); + if (missing.length > 0) { + allChapters.push(...missing.reverse()); + } } else { loadedCheerio('.wp-manga-chapter').each((_, element) => { const chap = parseChapterElement(element); - if (chap) chapters.push(chap); + if (chap) allChapters.push(chap); }); - chapters.reverse(); + allChapters.reverse(); } - chapters.forEach((chapter, index) => { + // Assign sequential chapterNumber before filtering hidden chapters + allChapters.forEach((chapter, index) => { chapter.chapterNumber = index + 1; }); - novel.chapters = chapters; + novel.chapters = this.hideLocked + ? allChapters.filter(c => !c.isLocked) + : allChapters; return novel; }