serializer.go 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  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.Header.Title = "Miniflux"
  32. opmlDocument.Header.DateCreated = time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST")
  33. groupedSubs := groupSubscriptionsByFeed(subscriptions)
  34. categories := make([]string, 0, len(groupedSubs))
  35. for k := range groupedSubs {
  36. categories = append(categories, k)
  37. }
  38. sort.Strings(categories)
  39. for _, categoryName := range categories {
  40. category := opmlOutline{Text: categoryName, Outlines: make(opmlOutlineCollection, 0, len(groupedSubs[categoryName]))}
  41. for _, subscription := range groupedSubs[categoryName] {
  42. category.Outlines = append(category.Outlines, opmlOutline{
  43. Title: subscription.Title,
  44. Text: subscription.Title,
  45. FeedURL: subscription.FeedURL,
  46. SiteURL: subscription.SiteURL,
  47. Description: subscription.Description,
  48. })
  49. }
  50. opmlDocument.Outlines = append(opmlDocument.Outlines, category)
  51. }
  52. return opmlDocument
  53. }
  54. func groupSubscriptionsByFeed(subscriptions []subcription) map[string][]subcription {
  55. groups := make(map[string][]subcription)
  56. for _, subscription := range subscriptions {
  57. groups[subscription.CategoryName] = append(groups[subscription.CategoryName], subscription)
  58. }
  59. return groups
  60. }