Repository navigation
fix(lightnovelwp): parse chapter text when bottomnav is absent - #2593
rajarsheechatterjee merged 2 commits into
Conversation
parseChapter anchored the chapter text on a `bottomnav` div to close the `epcontent` block. Current versions of the theme no longer emit that wrapper, so the match returned undefined and every chapter parsed as an empty string — no error, just blank text on affected sources. Close the block at whichever structural landmark follows it (bottomnav, a script tag, or </body>), and fall back to the whole document when no epcontent block is present at all. This also drops the regex's hard-coded `epcontent ` class spelling, which would not match `class="epcontent entry-content"` when epcontent is the only class. Output is byte-identical to the old expression on pages that still have bottomnav, verified against captured markup, so the other lightnovelwp sources are unaffected. Kol Novel was the source that surfaced this. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
| // block off at the next structural landmark instead, whichever is | ||
| // present, and fall back to the whole document when none of them is. | ||
| const content = data.match( | ||
| /<div[^>]*class="[^"]*\bepcontent\b[^"]*"[^>]*>([^]*?)(?=<div[^>]*class="?bottomnav|<script|<\/body)/, |
There was a problem hiding this comment.
Inline scripts truncate chapters If a chapter contains an inline
<script> before later paragraphs, this match stops at the script. Paragraph extraction then uses only the text before it, so the rest of the chapter silently disappears—even on pages where bottomnav previously let those paragraphs be parsed.
| // block off at the next structural landmark instead, whichever is | ||
| // present, and fall back to the whole document when none of them is. | ||
| const content = data.match( | ||
| /<div[^>]*class="[^"]*\bepcontent\b[^"]*"[^>]*>([^]*?)(?=<div[^>]*class="?bottomnav|<script|<\/body)/, |
There was a problem hiding this comment.
| .match(/<div.*?class="epcontent ([^]*?)<div.*?class="?bottomnav/g)?.[0] | ||
| .match(/<p[^>]*>([^]*?)<\/p>/g) | ||
| ?.join('\n') || '' | ||
| (content?.[1] ?? data).match(/<p[^>]*>([^]*?)<\/p>/g)?.join('\n') || '' |
There was a problem hiding this comment.
Follow-up to the bottomnav fix. Cutting the document at the next `<script>` or `</body>` guessed the boundary from surrounding text, which is wrong in both directions on a real page: - an inline `<script>` inside the block ends the match early, so paragraphs after it are dropped — measured on Kol Novel, the first script after the block cuts 6 of 96 paragraphs - when no script intervenes the match runs past the block's real close, so paragraphs from recommendations and comments are appended to the chapter — the same page yields 145 paragraphs that way against 96 inside the block Walk the markup with the parser instead and close on the element that actually ends the block, tracking div depth. This drops the first and last false landmark in one change rather than picking a better guess. Also return nothing when there is no epcontent block at all. A 200 response from a login wall or an error page has paragraphs but no chapter, and falling back to the whole document showed that page's text as the chapter. Verified against captured Kol Novel markup: 96 paragraphs inside the block, and an error page now yields an empty chapter rather than its notice text. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
All three review findings were right, and the first round of this PR was wrong. Rewritten rather than patched. The version that was up for review cut the document at the first
So both failure modes were live at once: the script boundary truncated the tail, and the Now the parser walks the markup with htmlparser2 and tracks The regex: /<div[^>]*class="[^"]*\bepcontent\b[^"]*"[^>]*>([^]*?)(?=<div[^>]*class="?bottomnav|<script|<\/body)/becomes a depth-tracked walk — enter on a On the error-page finding — agreed, and it is the one that needed a decision rather than a tweak. A 200 response from a login wall or an error page has paragraphs but no chapter, so falling back to the whole document showed the notice as chapter text. With no Verified against the captured page: 96 paragraphs, the same set the element actually contains. An error page and a login wall both return empty. 🤖 Generated with Claude Code |
|
Heads-up: #2596 and #2597 opened today report the same empty Kol Novel chapters (including Mushoku Tensei intro). Your depth-walk rewrite looks like the cover. If your verification confirms, consider adding Closes #2596, #2597 to the body. #2529 also claims Kol Novel coverage — worth a note on overlap to avoid double-landing. |
|
Verified the rewrite against live sites rather than the captured page. The three findings are addressed. Two things need your call before this merges — one is a bug in the rewrite, the other is an overlap with #2529 that is larger than it looks. The three findings, re-checkedEach finding reproduced on a page built to exhibit it, run against the branch implementation:
The depth-tracked walk is the right call — closing on a structural landmark was the actual defect, and the script-truncation and overrun findings were both real consequences of guessing one. 1. The walk misses a live source, because
|
| source | tag | in element | current walk | name-agnostic |
|---|---|---|---|---|
| TCSega | article | 26 | 0 | 26 |
| universalnovel | div | 131 | 131 | 131 |
| kodekslibrary | div | 113 | 113 | 113 |
| blumeverse | div | 140 | 140 | 140 |
| knoxt | div | 54 | 53 | 53 |
| lazygirltranslations | div | 58 | 58 | 58 |
| dobynovels | div | 46 | 46 | 46 |
| transweaver | div | 33 | 33 | 33 |
| hyacinthbloom | div | 4 | 4 | 4 |
One site recovered, eight byte-identical, none worse.
Two counts that look alarming and are not, so nobody re-derives them: kodekslibrary has 220 <p> in the block but 113 real ones — the other 107 are spacers, which the old code was returning as chapter text. knoxt returns 53 against 54 because one is a spacer.
2. #2529 already fixes this, and the two conflict directly
#2529 touches the same two files — lightnovelwp/template.ts and madara/template.ts — and fixes the same defects:
- its
lightnovelwpchange already handles the<article>case, by selecting$('.epcontent')with cheerio instead of hard-coding<div>, which is why it does not have the TCSega problem - its
madarachange replaces the same.text-left || .text-right || …chain I hit, where a cheerio selection is always truthy so||never falls through - it carries the same
h1.nhv-novel-title/.nhv-novel-cover/.nhv-novel-synopsisfallbacks that are the Riwyat half of my local work
Two different approaches to the same parseChapter bug on the same lines. Whichever lands second has to reconcile them, and the depth-tracked walk is the stronger of the two — it is what makes the three findings pass — so the reconciliation is worth doing deliberately rather than by whichever merge order Git picks.
On the two body edits you asked for: Closes #2596, #2597 is right, and I checked it does not collide — #2529 closes a different set of Kol Novel reports (#2568, #2576, #2578), so these two are still unclaimed and adding them here is the only place they get closed. I have not edited the body myself, since this is your branch; say the word and I will, or leave it to you.
The overlap note is the part worth your call.
Problem
parseChaptermatched the chapter text with:It relied on a
bottomnavdiv to close theepcontentblock. Current versions of the theme no longer emit that wrapper — the block is nowclass="epcontent entry-content"with nobottomnavanywhere in the document.The result is a silent failure: the match returns
undefined, the?.collapses toundefined, andparseChapterreturns''. No error is raised and no exception is thrown — the source just shows every chapter as blank text.Fix
Close the
epcontentblock at whichever structural landmark follows it (bottomnav, a<script>, or</body>), and fall back to the whole document when there is noepcontentblock at all:This also drops the regex's hard-coded
epcontentclass spelling, which would not match whenepcontentis not followed by a space and another class name.Verification
Against real captured markup from Kol Novel, whose current theme has no
bottomnav:Backward compatibility was checked rather than assumed, since this template backs 27 active sources:
epcontent+bottomnav, old and new expressions produce byte-identical output (97 bytes)bottomnav: old → 0 bytes, new → 60 bytesepcontentat all, the new code falls back instead of throwingparseNovelsandparseNovelare untouched and still parse 20 novels and 737 chapters respectively on the same pages.🤖 Generated with Claude Code