fix(backend): strip build hash in poller chapter scoping
This commit is contained in:
@@ -14,7 +14,9 @@ type latestChapter struct {
|
|||||||
|
|
||||||
// asuraSlugRe pulls the series slug out of a stored series_url.
|
// asuraSlugRe pulls the series slug out of a stored series_url.
|
||||||
// Shape verified live 2026-07-26: https://asurascans.com/comics/<slug>, where
|
// Shape verified live 2026-07-26: https://asurascans.com/comics/<slug>, where
|
||||||
// the slug carries a trailing hash-like suffix (e.g. "-f886a8af").
|
// the slug carries a trailing build-hash suffix (e.g. "-f886a8af") that
|
||||||
|
// rotates on every site redeploy — callers must strip it (asuraBuildHash)
|
||||||
|
// before using the slug to scope anything.
|
||||||
var asuraSlugRe = regexp.MustCompile(`/comics/([^/?#]+)`)
|
var asuraSlugRe = regexp.MustCompile(`/comics/([^/?#]+)`)
|
||||||
|
|
||||||
// demonicChapterRe matches the pre-redirect anchors demonic series pages link
|
// demonicChapterRe matches the pre-redirect anchors demonic series pages link
|
||||||
@@ -47,9 +49,14 @@ func latestChapterFrom(site, seriesURL, body string) (latestChapter, bool) {
|
|||||||
if m == nil {
|
if m == nil {
|
||||||
return latestChapter{}, false
|
return latestChapter{}, false
|
||||||
}
|
}
|
||||||
|
// Stored URLs predating a redeploy may carry a stale build hash;
|
||||||
|
// chapter hrefs in the fetched body carry the current one. Strip to
|
||||||
|
// the stable ID (same rule as migrateAsuraKeys) and make the hash
|
||||||
|
// optional in the pattern, so scoping survives rotations.
|
||||||
|
slug := asuraBuildHash.ReplaceAllString(m[1], "")
|
||||||
// Compiled per call rather than cached: this runs once per fetch, which
|
// Compiled per call rather than cached: this runs once per fetch, which
|
||||||
// is at most a few times a minute, and the slug varies per series.
|
// is at most a few times a minute, and the slug varies per series.
|
||||||
re = regexp.MustCompile(`/comics/` + regexp.QuoteMeta(m[1]) + `/chapter/([0-9.]+)`)
|
re = regexp.MustCompile(`/comics/` + regexp.QuoteMeta(slug) + `(?:-[0-9a-f]{8})?/chapter/([0-9.]+)`)
|
||||||
case "demonic":
|
case "demonic":
|
||||||
re = demonicChapterRe
|
re = demonicChapterRe
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -57,6 +57,13 @@ func TestLatestChapterFrom(t *testing.T) {
|
|||||||
site: "asura", seriesURL: asuraURL, body: asuraCrossSeriesFixture,
|
site: "asura", seriesURL: asuraURL, body: asuraCrossSeriesFixture,
|
||||||
wantOK: true, wantNum: 181, wantLabel: "Chapter 181",
|
wantOK: true, wantNum: 181, wantLabel: "Chapter 181",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "asura scoping survives a build-hash rotation",
|
||||||
|
site: "asura",
|
||||||
|
seriesURL: "https://asurascans.com/comics/chronicles-of-the-demon-faction-059befe1",
|
||||||
|
body: asuraCrossSeriesFixture,
|
||||||
|
wantOK: true, wantNum: 181, wantLabel: "Chapter 181",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "asura with an unparseable series url",
|
name: "asura with an unparseable series url",
|
||||||
site: "asura", seriesURL: "https://asurascans.com/", body: asuraSeriesFixture,
|
site: "asura", seriesURL: "https://asurascans.com/", body: asuraSeriesFixture,
|
||||||
|
|||||||
Reference in New Issue
Block a user