feat(latest): parse newest chapter for novelfull and lightnovelworld

This commit is contained in:
2026-08-06 03:07:22 +07:00
parent d9d7a1c00d
commit c81e50c7f1
2 changed files with 104 additions and 0 deletions
+69
View File
@@ -52,6 +52,33 @@ const kaganeAPIFixture = `
{"book_id":"c","title":"Episode 40.5","chapter_no":"40.5","sort_no":40}]}
`
// Trimmed from https://novelfull.com/reverend-insanity.html fetched 2026-08-05.
// The page carries a newest-first "latest chapters" widget above an
// oldest-first paginated list, so the newest anchor is deliberately NOT last —
// only a maximum finds it. The final anchor belongs to another series and must
// be excluded by slug scoping.
const novelfullSeriesFixture = `
<div class="l-chapters">
<a href="/reverend-insanity/chapter-2334-fang-yuan-and-giant-sun.html">Chapter 2334</a>
<a href="/reverend-insanity/chapter-2333-three-venerables.html">Chapter 2333</a>
</div>
<ul class="list-chapter">
<li><a href="/reverend-insanity/chapter-1.html">Chapter 1</a></li>
<li><a href="/reverend-insanity/chapter-2.html">Chapter 2</a></li>
</ul>
<a href="/release-that-witch/chapter-9999.html">Chapter 9999</a>
`
// Trimmed from https://lightnovelworld.net/novel/a-will-eternal/ fetched
// 2026-08-05. Its chapter anchors are absolute and flat — /<slug>-chapter-<n>/
// at the site root, not under /novel/. The last anchor is another series'.
const lnwSeriesFixture = `
<a href="https://lightnovelworld.net/a-will-eternal-chapter-1/">Chapter 1</a>
<a href="https://lightnovelworld.net/a-will-eternal-chapter-1317/">Chapter 1317</a>
<a href="https://lightnovelworld.net/a-will-eternal-chapter-1298/">Chapter 1298</a>
<a href="https://lightnovelworld.net/overgeared-chapter-9999/">Chapter 9999</a>
`
func TestLatestChapterFrom(t *testing.T) {
const asuraURL = "https://asurascans.com/comics/chronicles-of-the-demon-faction-f886a8af"
const demonicURL = "https://demonicscans.org/manga/Catastrophic-Necromancer"
@@ -146,6 +173,48 @@ func TestLatestChapterFrom(t *testing.T) {
body: challengeFixture,
wantOK: false,
},
{
name: "novelfull takes the max and ignores another series",
site: "novelfull",
seriesURL: "https://novelfull.com/reverend-insanity.html",
body: novelfullSeriesFixture,
wantOK: true, wantNum: 2334, wantLabel: "Chapter 2334",
},
{
name: "novelfull yields nothing on a challenge page",
site: "novelfull",
seriesURL: "https://novelfull.com/reverend-insanity.html",
body: challengeFixture,
wantOK: false,
},
{
name: "novelfull with an unparseable series url",
site: "novelfull",
seriesURL: "https://novelfull.com/genre/Fantasy",
body: novelfullSeriesFixture,
wantOK: false,
},
{
name: "lightnovelworld takes the max and ignores another series",
site: "lightnovelworld",
seriesURL: "https://lightnovelworld.net/novel/a-will-eternal/",
body: lnwSeriesFixture,
wantOK: true, wantNum: 1317, wantLabel: "Chapter 1317",
},
{
name: "lightnovelworld tolerates a series url with no trailing slash",
site: "lightnovelworld",
seriesURL: "https://lightnovelworld.net/novel/a-will-eternal",
body: lnwSeriesFixture,
wantOK: true, wantNum: 1317, wantLabel: "Chapter 1317",
},
{
name: "lightnovelworld yields nothing on a challenge page",
site: "lightnovelworld",
seriesURL: "https://lightnovelworld.net/novel/a-will-eternal/",
body: challengeFixture,
wantOK: false,
},
}
for _, tt := range tests {