116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
||
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
|
||
|
package atom // import "miniflux.app/v2/internal/reader/atom"
|
||
|
|
||
|
import (
|
||
|
"log/slog"
|
||
|
"time"
|
||
|
|
||
|
"miniflux.app/v2/internal/crypto"
|
||
|
"miniflux.app/v2/internal/model"
|
||
|
"miniflux.app/v2/internal/reader/date"
|
||
|
"miniflux.app/v2/internal/reader/sanitizer"
|
||
|
"miniflux.app/v2/internal/urllib"
|
||
|
)
|
||
|
|
||
|
type Atom03Adapter struct {
|
||
|
atomFeed *Atom03Feed
|
||
|
}
|
||
|
|
||
|
func NewAtom03Adapter(atomFeed *Atom03Feed) *Atom03Adapter {
|
||
|
return &Atom03Adapter{atomFeed}
|
||
|
}
|
||
|
|
||
|
func (a *Atom03Adapter) BuildFeed(baseURL string) *model.Feed {
|
||
|
feed := new(model.Feed)
|
||
|
|
||
|
// Populate the feed URL.
|
||
|
feedURL := a.atomFeed.Links.firstLinkWithRelation("self")
|
||
|
if feedURL != "" {
|
||
|
if absoluteFeedURL, err := urllib.AbsoluteURL(baseURL, feedURL); err == nil {
|
||
|
feed.FeedURL = absoluteFeedURL
|
||
|
}
|
||
|
} else {
|
||
|
feed.FeedURL = baseURL
|
||
|
}
|
||
|
|
||
|
// Populate the site URL.
|
||
|
siteURL := a.atomFeed.Links.OriginalLink()
|
||
|
if siteURL != "" {
|
||
|
if absoluteSiteURL, err := urllib.AbsoluteURL(baseURL, siteURL); err == nil {
|
||
|
feed.SiteURL = absoluteSiteURL
|
||
|
}
|
||
|
} else {
|
||
|
feed.SiteURL = baseURL
|
||
|
}
|
||
|
|
||
|
// Populate the feed title.
|
||
|
feed.Title = a.atomFeed.Title.Content()
|
||
|
if feed.Title == "" {
|
||
|
feed.Title = feed.SiteURL
|
||
|
}
|
||
|
|
||
|
for _, atomEntry := range a.atomFeed.Entries {
|
||
|
entry := model.NewEntry()
|
||
|
|
||
|
// Populate the entry URL.
|
||
|
entry.URL = atomEntry.Links.OriginalLink()
|
||
|
if entry.URL != "" {
|
||
|
if absoluteEntryURL, err := urllib.AbsoluteURL(feed.SiteURL, entry.URL); err == nil {
|
||
|
entry.URL = absoluteEntryURL
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Populate the entry content.
|
||
|
entry.Content = atomEntry.Content.Content()
|
||
|
if entry.Content == "" {
|
||
|
entry.Content = atomEntry.Summary.Content()
|
||
|
}
|
||
|
|
||
|
// Populate the entry title.
|
||
|
entry.Title = atomEntry.Title.Content()
|
||
|
if entry.Title == "" {
|
||
|
entry.Title = sanitizer.TruncateHTML(entry.Content, 100)
|
||
|
}
|
||
|
if entry.Title == "" {
|
||
|
entry.Title = entry.URL
|
||
|
}
|
||
|
|
||
|
// Populate the entry author.
|
||
|
entry.Author = atomEntry.Author.PersonName()
|
||
|
if entry.Author == "" {
|
||
|
entry.Author = a.atomFeed.Author.PersonName()
|
||
|
}
|
||
|
|
||
|
// Populate the entry date.
|
||
|
for _, value := range []string{atomEntry.Issued, atomEntry.Modified, atomEntry.Created} {
|
||
|
if parsedDate, err := date.Parse(value); err == nil {
|
||
|
entry.Date = parsedDate
|
||
|
break
|
||
|
} else {
|
||
|
slog.Debug("Unable to parse date from Atom 0.3 feed",
|
||
|
slog.String("date", value),
|
||
|
slog.String("id", atomEntry.ID),
|
||
|
slog.Any("error", err),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
if entry.Date.IsZero() {
|
||
|
entry.Date = time.Now()
|
||
|
}
|
||
|
|
||
|
// Generate the entry hash.
|
||
|
for _, value := range []string{atomEntry.ID, atomEntry.Links.OriginalLink()} {
|
||
|
if value != "" {
|
||
|
entry.Hash = crypto.Hash(value)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
feed.Entries = append(feed.Entries, entry)
|
||
|
}
|
||
|
|
||
|
return feed
|
||
|
}
|