2023-06-19 23:42:47 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2017-11-21 03:34:11 +01:00
|
|
|
|
2023-08-11 04:46:45 +02:00
|
|
|
package rdf // import "miniflux.app/v2/internal/reader/rdf"
|
2017-11-21 03:34:11 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
2021-03-20 02:39:44 +01:00
|
|
|
"html"
|
2023-09-25 01:32:09 +02:00
|
|
|
"log/slog"
|
2017-11-22 23:52:31 +01:00
|
|
|
"strings"
|
2017-11-21 04:25:30 +01:00
|
|
|
"time"
|
2017-11-21 03:34:11 +01:00
|
|
|
|
2023-08-11 04:46:45 +02:00
|
|
|
"miniflux.app/v2/internal/crypto"
|
|
|
|
"miniflux.app/v2/internal/model"
|
|
|
|
"miniflux.app/v2/internal/reader/date"
|
2023-09-09 01:50:06 +02:00
|
|
|
"miniflux.app/v2/internal/reader/dublincore"
|
2023-08-11 04:46:45 +02:00
|
|
|
"miniflux.app/v2/internal/reader/sanitizer"
|
2023-08-14 04:09:01 +02:00
|
|
|
"miniflux.app/v2/internal/urllib"
|
2017-11-21 03:34:11 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type rdfFeed struct {
|
|
|
|
XMLName xml.Name `xml:"RDF"`
|
|
|
|
Title string `xml:"channel>title"`
|
|
|
|
Link string `xml:"channel>link"`
|
|
|
|
Items []rdfItem `xml:"item"`
|
2023-09-09 01:50:06 +02:00
|
|
|
dublincore.DublinCoreFeedElement
|
2017-11-21 03:34:11 +01:00
|
|
|
}
|
|
|
|
|
2020-12-03 05:47:11 +01:00
|
|
|
func (r *rdfFeed) Transform(baseURL string) *model.Feed {
|
|
|
|
var err error
|
2017-11-21 03:34:11 +01:00
|
|
|
feed := new(model.Feed)
|
|
|
|
feed.Title = sanitizer.StripTags(r.Title)
|
2020-12-03 05:47:11 +01:00
|
|
|
feed.FeedURL = baseURL
|
2023-08-14 04:09:01 +02:00
|
|
|
feed.SiteURL, err = urllib.AbsoluteURL(baseURL, r.Link)
|
2020-12-03 05:47:11 +01:00
|
|
|
if err != nil {
|
|
|
|
feed.SiteURL = r.Link
|
|
|
|
}
|
2017-11-21 03:34:11 +01:00
|
|
|
|
|
|
|
for _, item := range r.Items {
|
|
|
|
entry := item.Transform()
|
2019-12-23 23:39:54 +01:00
|
|
|
if entry.Author == "" && r.DublinCoreCreator != "" {
|
2023-09-09 01:50:06 +02:00
|
|
|
entry.Author = r.GetSanitizedCreator()
|
2017-11-21 03:34:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if entry.URL == "" {
|
|
|
|
entry.URL = feed.SiteURL
|
2017-12-14 05:16:15 +01:00
|
|
|
} else {
|
2023-08-14 04:09:01 +02:00
|
|
|
entryURL, err := urllib.AbsoluteURL(feed.SiteURL, entry.URL)
|
2017-12-14 05:16:15 +01:00
|
|
|
if err == nil {
|
|
|
|
entry.URL = entryURL
|
|
|
|
}
|
2017-11-21 03:34:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
feed.Entries = append(feed.Entries, entry)
|
|
|
|
}
|
|
|
|
|
|
|
|
return feed
|
|
|
|
}
|
|
|
|
|
|
|
|
type rdfItem struct {
|
|
|
|
Title string `xml:"title"`
|
|
|
|
Link string `xml:"link"`
|
|
|
|
Description string `xml:"description"`
|
2023-09-09 01:50:06 +02:00
|
|
|
dublincore.DublinCoreItemElement
|
2017-11-21 03:34:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rdfItem) Transform() *model.Entry {
|
2023-09-09 07:45:17 +02:00
|
|
|
entry := model.NewEntry()
|
2019-12-23 23:39:54 +01:00
|
|
|
entry.Title = r.entryTitle()
|
|
|
|
entry.Author = r.entryAuthor()
|
|
|
|
entry.URL = r.entryURL()
|
|
|
|
entry.Content = r.entryContent()
|
|
|
|
entry.Hash = r.entryHash()
|
|
|
|
entry.Date = r.entryDate()
|
2017-11-21 03:34:11 +01:00
|
|
|
return entry
|
|
|
|
}
|
|
|
|
|
2019-12-23 23:39:54 +01:00
|
|
|
func (r *rdfItem) entryTitle() string {
|
2021-03-20 02:39:44 +01:00
|
|
|
return html.UnescapeString(strings.TrimSpace(r.Title))
|
2019-12-23 23:39:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rdfItem) entryContent() string {
|
|
|
|
switch {
|
|
|
|
case r.DublinCoreContent != "":
|
|
|
|
return r.DublinCoreContent
|
|
|
|
default:
|
|
|
|
return r.Description
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rdfItem) entryAuthor() string {
|
2023-09-09 01:50:06 +02:00
|
|
|
return r.GetSanitizedCreator()
|
2019-12-23 23:39:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rdfItem) entryURL() string {
|
|
|
|
return strings.TrimSpace(r.Link)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rdfItem) entryDate() time.Time {
|
|
|
|
if r.DublinCoreDate != "" {
|
|
|
|
result, err := date.Parse(r.DublinCoreDate)
|
2018-04-11 03:13:05 +02:00
|
|
|
if err != nil {
|
2023-09-25 01:32:09 +02:00
|
|
|
slog.Warn("Unable to parse date from RDF feed",
|
|
|
|
slog.String("date", r.DublinCoreDate),
|
|
|
|
slog.String("link", r.Link),
|
|
|
|
slog.Any("error", err),
|
|
|
|
)
|
2018-04-11 03:13:05 +02:00
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
|
2019-12-23 23:39:54 +01:00
|
|
|
func (r *rdfItem) entryHash() string {
|
2017-11-21 03:34:11 +01:00
|
|
|
value := r.Link
|
|
|
|
if value == "" {
|
|
|
|
value = r.Title + r.Description
|
|
|
|
}
|
|
|
|
|
2018-01-03 04:15:08 +01:00
|
|
|
return crypto.Hash(value)
|
2017-11-21 03:34:11 +01:00
|
|
|
}
|