serializer.go 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package opml // import "miniflux.app/v2/internal/reader/opml"
  4. import (
  5. "bufio"
  6. "bytes"
  7. "encoding/xml"
  8. "log/slog"
  9. "sort"
  10. "time"
  11. )
  12. // serialize returns a SubcriptionList in OPML format.
  13. func serialize(subscriptions []subcription) string {
  14. var b bytes.Buffer
  15. writer := bufio.NewWriter(&b)
  16. writer.WriteString(xml.Header)
  17. opmlDocument := convertSubscriptionsToOPML(subscriptions)
  18. encoder := xml.NewEncoder(writer)
  19. encoder.Indent("", " ")
  20. if err := encoder.Encode(opmlDocument); err != nil {
  21. slog.Error("Unable to serialize OPML document",
  22. slog.Any("error", err),
  23. )
  24. return ""
  25. }
  26. return b.String()
  27. }
  28. func convertSubscriptionsToOPML(subscriptions []subcription) *opmlDocument {
  29. opmlDocument := &opmlDocument{}
  30. opmlDocument.Version = "2.0"
  31. opmlDocument.MinifluxNamespace = minifluxOPMLNamespace
  32. opmlDocument.Header.Title = "Miniflux"
  33. opmlDocument.Header.DateCreated = time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST")
  34. groupedSubs := groupSubscriptionsByFeed(subscriptions)
  35. categories := make([]string, 0, len(groupedSubs))
  36. for k := range groupedSubs {
  37. categories = append(categories, k)
  38. }
  39. sort.Strings(categories)
  40. for _, categoryName := range categories {
  41. category := opmlOutline{Text: categoryName, Outlines: make(opmlOutlineCollection, 0, len(groupedSubs[categoryName]))}
  42. for _, subscription := range groupedSubs[categoryName] {
  43. category.Outlines = append(category.Outlines, opmlOutline{
  44. Title: subscription.Title,
  45. Text: subscription.Title,
  46. FeedURL: subscription.FeedURL,
  47. SiteURL: subscription.SiteURL,
  48. Description: subscription.Description,
  49. ScraperRules: subscription.ScraperRules,
  50. RewriteRules: subscription.RewriteRules,
  51. UrlRewriteRules: subscription.UrlRewriteRules,
  52. BlocklistRules: subscription.BlocklistRules,
  53. KeeplistRules: subscription.KeeplistRules,
  54. BlockFilterEntryRules: subscription.BlockFilterEntryRules,
  55. KeepFilterEntryRules: subscription.KeepFilterEntryRules,
  56. UserAgent: subscription.UserAgent,
  57. Crawler: subscription.Crawler,
  58. IgnoreHTTPCache: subscription.IgnoreHTTPCache,
  59. FetchViaProxy: subscription.FetchViaProxy,
  60. Disabled: subscription.Disabled,
  61. NoMediaPlayer: subscription.NoMediaPlayer,
  62. HideGlobally: subscription.HideGlobally,
  63. AllowSelfSignedCertificates: subscription.AllowSelfSignedCertificates,
  64. DisableHTTP2: subscription.DisableHTTP2,
  65. IgnoreEntryUpdates: subscription.IgnoreEntryUpdates,
  66. })
  67. }
  68. opmlDocument.Outlines = append(opmlDocument.Outlines, category)
  69. }
  70. return opmlDocument
  71. }
  72. func groupSubscriptionsByFeed(subscriptions []subcription) map[string][]subcription {
  73. groups := make(map[string][]subcription)
  74. for _, subscription := range subscriptions {
  75. groups[subscription.CategoryName] = append(groups[subscription.CategoryName], subscription)
  76. }
  77. return groups
  78. }