mirror of
https://github.com/tiennm99/MTTools.git
synced 2026-10-19 06:15:28 +00:00
feat: parse novel tags and add a single-request metadata fetch
Novel gains Tags, read from the anchors carrying schema.org itemprop="genre". Matching that microdata rather than the /the-loai/ href shape is what keeps the site-wide genre navigation out: a sampled page links 69 categories against the novel's own 6. NovelInfo fetches just the landing page and parses it, so a caller that only wants metadata pays one request instead of the two Novel needs for its chapter list cross-check.
This commit is contained in:
1 parent
79cf77a471
commit
c1ea1876bb
3 files changed
+103
-3
No files matched your search
@@ -17,9 +17,13 @@ type ChapterRef struct {
|
||||
|
||||
// Novel is a novel's landing page: its title and its chapters in reading order.
|
||||
type Novel struct {
|
||||
Title string
|
||||
Slug string
|
||||
URL string
|
||||
Title string
|
||||
Slug string
|
||||
URL string
|
||||
|
||||
// Tags are the novel's own genres, as labelled on the site, in the order
|
||||
// they appear. Empty when the page lists none.
|
||||
Tags []string
|
||||
Chapters []ChapterRef
|
||||
}
|
||||
|
||||
@@ -43,6 +47,7 @@ func ParseNovelPage(page []byte, pageURL string) (*Novel, error) {
|
||||
Title: novelTitle(doc),
|
||||
Slug: slugFromNovelURL(base),
|
||||
URL: pageURL,
|
||||
Tags: tagsFromInfo(doc),
|
||||
Chapters: chapterRefsFromList(doc, base),
|
||||
}
|
||||
if novel.Title == "" {
|
||||
@@ -64,6 +69,35 @@ func novelTitle(doc *html.Node) string {
|
||||
return nodeText(elementByTag(doc, "title"))
|
||||
}
|
||||
|
||||
// tagsFromInfo reads the novel's own genres out of the info block.
|
||||
//
|
||||
// The anchors are matched on the schema.org itemprop="genre" microdata rather
|
||||
// than on their href. The page also carries a site-wide genre menu linking every
|
||||
// category — 69 distinct ones against this novel's 6 on a sampled page — so
|
||||
// matching the /the-loai/ URL shape would pull in the whole navigation.
|
||||
func tagsFromInfo(doc *html.Node) []string {
|
||||
links := findAllNodes(doc, func(n *html.Node) bool {
|
||||
return n.Type == html.ElementNode && n.Data == "a" && attr(n, "itemprop") == "genre"
|
||||
})
|
||||
|
||||
var tags []string
|
||||
seen := make(map[string]bool, len(links))
|
||||
for _, link := range links {
|
||||
// The label appears both as the link text and as its title attribute;
|
||||
// prefer the text and fall back to the attribute.
|
||||
name := nodeText(link)
|
||||
if name == "" {
|
||||
name = collapseSpaces(attr(link, "title"))
|
||||
}
|
||||
if name == "" || seen[name] {
|
||||
continue
|
||||
}
|
||||
seen[name] = true
|
||||
tags = append(tags, name)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// slugFromNovelURL turns https://host/tro-lai-nam-thang-cu.html into
|
||||
// "tro-lai-nam-thang-cu".
|
||||
func slugFromNovelURL(u *url.URL) string {
|
||||
|
||||
Reference in new issue
Block a user