mirror of
https://github.com/miniflux/v2.git
synced 2025-08-01 17:38:37 +00:00
Refactor Atom parser to use an adapter
This commit is contained in:
parent
2ba893bc79
commit
dd4fb660c1
11 changed files with 795 additions and 500 deletions
|
@ -3,77 +3,91 @@
|
|||
|
||||
package atom // import "miniflux.app/v2/internal/reader/atom"
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type atomPerson struct {
|
||||
Name string `xml:"name"`
|
||||
// Specs: https://datatracker.ietf.org/doc/html/rfc4287#section-3.2
|
||||
type AtomPerson struct {
|
||||
// The "atom:name" element's content conveys a human-readable name for the author.
|
||||
// It MAY be the name of a corporation or other entity no individual authors can be named.
|
||||
// Person constructs MUST contain exactly one "atom:name" element, whose content MUST be a string.
|
||||
Name string `xml:"name"`
|
||||
|
||||
// The "atom:email" element's content conveys an e-mail address associated with the Person construct.
|
||||
// Person constructs MAY contain an atom:email element, but MUST NOT contain more than one.
|
||||
// Its content MUST be an e-mail address [RFC2822].
|
||||
// Ordering of the element children of Person constructs MUST NOT be considered significant.
|
||||
Email string `xml:"email"`
|
||||
}
|
||||
|
||||
func (a *atomPerson) String() string {
|
||||
name := ""
|
||||
|
||||
switch {
|
||||
case a.Name != "":
|
||||
name = a.Name
|
||||
case a.Email != "":
|
||||
name = a.Email
|
||||
func (a *AtomPerson) PersonName() string {
|
||||
name := strings.TrimSpace(a.Name)
|
||||
if name != "" {
|
||||
return name
|
||||
}
|
||||
|
||||
return strings.TrimSpace(name)
|
||||
return strings.TrimSpace(a.Email)
|
||||
}
|
||||
|
||||
type atomAuthors []*atomPerson
|
||||
type AtomPersons []*AtomPerson
|
||||
|
||||
func (a atomAuthors) String() string {
|
||||
var authors []string
|
||||
func (a AtomPersons) PersonNames() []string {
|
||||
var names []string
|
||||
authorNamesMap := make(map[string]bool)
|
||||
|
||||
for _, person := range a {
|
||||
authors = append(authors, person.String())
|
||||
personName := person.PersonName()
|
||||
if _, ok := authorNamesMap[personName]; !ok {
|
||||
names = append(names, personName)
|
||||
authorNamesMap[personName] = true
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(authors, ", ")
|
||||
return names
|
||||
}
|
||||
|
||||
type atomLink struct {
|
||||
URL string `xml:"href,attr"`
|
||||
// Specs: https://datatracker.ietf.org/doc/html/rfc4287#section-4.2.7
|
||||
type AtomLink struct {
|
||||
Href string `xml:"href,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Rel string `xml:"rel,attr"`
|
||||
Length string `xml:"length,attr"`
|
||||
Title string `xml:"title,attr"`
|
||||
}
|
||||
|
||||
type atomLinks []*atomLink
|
||||
type AtomLinks []*AtomLink
|
||||
|
||||
func (a atomLinks) originalLink() string {
|
||||
func (a AtomLinks) OriginalLink() string {
|
||||
for _, link := range a {
|
||||
if strings.EqualFold(link.Rel, "alternate") {
|
||||
return strings.TrimSpace(link.URL)
|
||||
return strings.TrimSpace(link.Href)
|
||||
}
|
||||
|
||||
if link.Rel == "" && (link.Type == "" || link.Type == "text/html") {
|
||||
return strings.TrimSpace(link.URL)
|
||||
return strings.TrimSpace(link.Href)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a atomLinks) firstLinkWithRelation(relation string) string {
|
||||
func (a AtomLinks) firstLinkWithRelation(relation string) string {
|
||||
for _, link := range a {
|
||||
if strings.EqualFold(link.Rel, relation) {
|
||||
return strings.TrimSpace(link.URL)
|
||||
return strings.TrimSpace(link.Href)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a atomLinks) firstLinkWithRelationAndType(relation string, contentTypes ...string) string {
|
||||
func (a AtomLinks) firstLinkWithRelationAndType(relation string, contentTypes ...string) string {
|
||||
for _, link := range a {
|
||||
if strings.EqualFold(link.Rel, relation) {
|
||||
for _, contentType := range contentTypes {
|
||||
if strings.EqualFold(link.Type, contentType) {
|
||||
return strings.TrimSpace(link.URL)
|
||||
return strings.TrimSpace(link.Href)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,3 +95,46 @@ func (a atomLinks) firstLinkWithRelationAndType(relation string, contentTypes ..
|
|||
|
||||
return ""
|
||||
}
|
||||
|
||||
// The "atom:category" element conveys information about a category
|
||||
// associated with an entry or feed. This specification assigns no
|
||||
// meaning to the content (if any) of this element.
|
||||
//
|
||||
// Specs: https://datatracker.ietf.org/doc/html/rfc4287#section-4.2.2
|
||||
type AtomCategory struct {
|
||||
// The "term" attribute is a string that identifies the category to
|
||||
// which the entry or feed belongs. Category elements MUST have a
|
||||
// "term" attribute.
|
||||
Term string `xml:"term,attr"`
|
||||
|
||||
// The "scheme" attribute is an IRI that identifies a categorization
|
||||
// scheme. Category elements MAY have a "scheme" attribute.
|
||||
Scheme string `xml:"scheme,attr"`
|
||||
|
||||
// The "label" attribute provides a human-readable label for display in
|
||||
// end-user applications. The content of the "label" attribute is
|
||||
// Language-Sensitive. Entities such as "&" and "<" represent
|
||||
// their corresponding characters ("&" and "<", respectively), not
|
||||
// markup. Category elements MAY have a "label" attribute.
|
||||
Label string `xml:"label,attr"`
|
||||
}
|
||||
|
||||
type AtomCategories []AtomCategory
|
||||
|
||||
func (ac AtomCategories) CategoryNames() []string {
|
||||
var categories []string
|
||||
|
||||
for _, category := range ac {
|
||||
label := strings.TrimSpace(category.Label)
|
||||
if label != "" {
|
||||
categories = append(categories, label)
|
||||
} else {
|
||||
term := strings.TrimSpace(category.Term)
|
||||
if term != "" {
|
||||
categories = append(categories, term)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return categories
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue