atom_03_adapter.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package atom // import "miniflux.app/v2/internal/reader/atom"
  4. import (
  5. "log/slog"
  6. "time"
  7. "miniflux.app/v2/internal/crypto"
  8. "miniflux.app/v2/internal/model"
  9. "miniflux.app/v2/internal/reader/date"
  10. "miniflux.app/v2/internal/reader/sanitizer"
  11. "miniflux.app/v2/internal/urllib"
  12. )
  13. type atom03Adapter struct {
  14. atomFeed *atom03Feed
  15. }
  16. func (a *atom03Adapter) buildFeed(baseURL string) *model.Feed {
  17. feed := new(model.Feed)
  18. // Populate the feed URL.
  19. feedURL := a.atomFeed.Links.firstLinkWithRelation("self")
  20. if feedURL != "" {
  21. if absoluteFeedURL, err := urllib.ResolveToAbsoluteURL(baseURL, feedURL); err == nil {
  22. feed.FeedURL = absoluteFeedURL
  23. }
  24. } else {
  25. feed.FeedURL = baseURL
  26. }
  27. // Populate the site URL.
  28. siteURL := a.atomFeed.Links.originalLink()
  29. if siteURL != "" {
  30. if absoluteSiteURL, err := urllib.ResolveToAbsoluteURL(baseURL, siteURL); err == nil {
  31. feed.SiteURL = absoluteSiteURL
  32. }
  33. } else {
  34. feed.SiteURL = baseURL
  35. }
  36. // Populate the feed title.
  37. feed.Title = a.atomFeed.Title.content()
  38. if feed.Title == "" {
  39. feed.Title = feed.SiteURL
  40. }
  41. for _, atomEntry := range a.atomFeed.Entries {
  42. entry := model.NewEntry()
  43. // Populate the entry URL.
  44. entry.URL = atomEntry.Links.originalLink()
  45. if entry.URL != "" {
  46. if absoluteEntryURL, err := urllib.ResolveToAbsoluteURL(feed.SiteURL, entry.URL); err == nil {
  47. entry.URL = absoluteEntryURL
  48. }
  49. }
  50. // Populate the entry content.
  51. entry.Content = atomEntry.Content.content()
  52. if entry.Content == "" {
  53. entry.Content = atomEntry.Summary.content()
  54. }
  55. // Populate the entry title.
  56. entry.Title = atomEntry.Title.content()
  57. if entry.Title == "" {
  58. entry.Title = sanitizer.TruncateHTML(entry.Content, 100)
  59. }
  60. if entry.Title == "" {
  61. entry.Title = entry.URL
  62. }
  63. // Populate the entry author.
  64. entry.Author = atomEntry.Author.PersonName()
  65. if entry.Author == "" {
  66. entry.Author = a.atomFeed.Author.PersonName()
  67. }
  68. // Populate the entry date.
  69. for _, value := range []string{atomEntry.Issued, atomEntry.Modified, atomEntry.Created} {
  70. if parsedDate, err := date.Parse(value); err == nil {
  71. entry.Date = parsedDate
  72. break
  73. } else {
  74. slog.Debug("Unable to parse date from Atom 0.3 feed",
  75. slog.String("date", value),
  76. slog.String("id", atomEntry.ID),
  77. slog.Any("error", err),
  78. )
  79. }
  80. }
  81. if entry.Date.IsZero() {
  82. entry.Date = time.Now()
  83. }
  84. // Generate the entry hash.
  85. for _, value := range []string{atomEntry.ID, atomEntry.Links.originalLink()} {
  86. if value != "" {
  87. entry.Hash = crypto.SHA256(value)
  88. break
  89. }
  90. }
  91. feed.Entries = append(feed.Entries, entry)
  92. }
  93. return feed
  94. }