feat(listing): populate Tags and CategorizedTags from figure data-tags
FA's beta listing pages emit each submission's tag list on the
figure's <img data-tags="..."> attribute, mixing prefixed system tags
(s_/c_/a_/u_/t_) with the unprefixed keyword list. Reading it during
gallery-page parse lets callers classify favorites/gallery/scraps/
browse/search/inbox items at scrape time, avoiding a /view/{id}
round-trip per submission.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,99 @@ func TestParseGalleryPage_Synthetic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseGalleryFigure_DataTags(t *testing.T) {
|
||||
const html = `<html><body>
|
||||
<figure id="sid-2001" class="t-image r-general">
|
||||
<a href="/view/2001/" title="Mixed Tags">
|
||||
<img data-tags="u_someartist c_artwork_digital t_all s_wolf wolf solo digital landscape" src="//d.example/thumb/2001.png"/>
|
||||
</a>
|
||||
</figure>
|
||||
<figure id="sid-2002" class="t-image r-general">
|
||||
<a href="/view/2002/" title="No Tags">
|
||||
<img src="//d.example/thumb/2002.png"/>
|
||||
</a>
|
||||
</figure>
|
||||
<figure id="sid-2003" class="t-image r-general">
|
||||
<a href="/view/2003/" title="Only Keywords">
|
||||
<img data-tags="wolf solo" src="//d.example/thumb/2003.png"/>
|
||||
</a>
|
||||
</figure>
|
||||
</body></html>`
|
||||
doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
|
||||
if err != nil {
|
||||
t.Fatalf("setup: %v", err)
|
||||
}
|
||||
items, _ := parseGalleryPage(doc, false)
|
||||
if len(items) != 3 {
|
||||
t.Fatalf("items = %d; want 3", len(items))
|
||||
}
|
||||
|
||||
// Mixed prefixed + unprefixed.
|
||||
mixed := items[0]
|
||||
wantTags := []string{"wolf", "solo", "digital", "landscape"}
|
||||
if !equalStrings(mixed.Tags, wantTags) {
|
||||
t.Errorf("items[0].Tags = %v; want %v", mixed.Tags, wantTags)
|
||||
}
|
||||
if !equalStrings(mixed.CategorizedTags.Species, []string{"wolf"}) {
|
||||
t.Errorf("items[0].Species = %v", mixed.CategorizedTags.Species)
|
||||
}
|
||||
if !equalStrings(mixed.CategorizedTags.Characters, []string{"artwork_digital"}) {
|
||||
t.Errorf("items[0].Characters = %v", mixed.CategorizedTags.Characters)
|
||||
}
|
||||
if !equalStrings(mixed.CategorizedTags.Types, []string{"all"}) {
|
||||
t.Errorf("items[0].Types = %v", mixed.CategorizedTags.Types)
|
||||
}
|
||||
if !equalStrings(mixed.CategorizedTags.Artists, []string{"someartist"}) {
|
||||
t.Errorf("items[0].Artists = %v", mixed.CategorizedTags.Artists)
|
||||
}
|
||||
|
||||
// Missing data-tags: both slices stay nil.
|
||||
if items[1].Tags != nil {
|
||||
t.Errorf("items[1].Tags = %v; want nil", items[1].Tags)
|
||||
}
|
||||
if items[1].CategorizedTags.Species != nil ||
|
||||
items[1].CategorizedTags.Characters != nil ||
|
||||
items[1].CategorizedTags.Artists != nil ||
|
||||
items[1].CategorizedTags.Types != nil {
|
||||
t.Errorf("items[1].CategorizedTags = %+v; want zero", items[1].CategorizedTags)
|
||||
}
|
||||
|
||||
// Unprefixed-only: everything lands in Tags.
|
||||
if !equalStrings(items[2].Tags, []string{"wolf", "solo"}) {
|
||||
t.Errorf("items[2].Tags = %v", items[2].Tags)
|
||||
}
|
||||
if items[2].CategorizedTags.Species != nil {
|
||||
t.Errorf("items[2].Species = %v; want nil", items[2].CategorizedTags.Species)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseGalleryPage_RealFixtureTags(t *testing.T) {
|
||||
raw := loadFixture(t, "gallery_page1.html")
|
||||
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(raw))
|
||||
if err != nil {
|
||||
t.Fatalf("read doc: %v", err)
|
||||
}
|
||||
items, _ := parseGalleryPage(doc, false)
|
||||
if len(items) == 0 {
|
||||
t.Fatal("real fixture: no items parsed")
|
||||
}
|
||||
var withTags, withSpecies int
|
||||
for _, it := range items {
|
||||
if len(it.Tags) > 0 {
|
||||
withTags++
|
||||
}
|
||||
if len(it.CategorizedTags.Species) > 0 {
|
||||
withSpecies++
|
||||
}
|
||||
}
|
||||
if withTags == 0 {
|
||||
t.Error("no items got Tags populated from data-tags")
|
||||
}
|
||||
if withSpecies == 0 {
|
||||
t.Error("no items got CategorizedTags.Species populated from data-tags")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseGalleryPage_RealFixture(t *testing.T) {
|
||||
raw := loadFixture(t, "gallery_page1.html")
|
||||
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(raw))
|
||||
|
||||
Reference in New Issue
Block a user