Helper scripts and tools for GoBlog
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
2.8 KiB

  1. package main
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "flag"
  6. "fmt"
  7. "io/ioutil"
  8. "net/http"
  9. "os"
  10. "sort"
  11. "time"
  12. )
  13. // This script downloads the OPML export from Miniflux, applies a filter and saves the result as a json document to use for a blogroll
  14. type opml struct {
  15. Body struct {
  16. opmlOutline
  17. } `xml:"body" json:"body"`
  18. }
  19. type opmlOutline struct {
  20. Text string `xml:"text,attr" json:"_text,omitempty"`
  21. Title string `xml:"title,attr" json:"_title,omitempty"`
  22. XMLURL string `xml:"xmlUrl,attr" json:"_xmlUrl,omitempty"`
  23. HTMLURL string `xml:"htmlUrl,attr" json:"_htmlUrl,omitempty"`
  24. Outlines []opmlOutline `xml:"outline" json:"outline,omitempty"`
  25. }
  26. type flagArray []string
  27. func (i *flagArray) String() string {
  28. return fmt.Sprint(*i)
  29. }
  30. func (i *flagArray) Set(value string) error {
  31. *i = append(*i, value)
  32. return nil
  33. }
  34. func main() {
  35. var categories flagArray
  36. flag.Var(&categories, "c", "Allowed categories (specify multiple times for multiple categories)")
  37. var instance, token, output string
  38. flag.StringVar(&instance, "i", "", "Miniflux instance to use")
  39. flag.StringVar(&token, "t", "", "Token to use for the Miniflux API")
  40. flag.StringVar(&output, "o", "opml.json", "Output file to write to")
  41. flag.Parse()
  42. if len(categories) == 0 || instance == "" || token == "" {
  43. fmt.Println("Not all required flags provided")
  44. os.Exit(1)
  45. return
  46. }
  47. // Get OPML
  48. client := http.Client{
  49. Timeout: time.Second * 5,
  50. }
  51. req, err := http.NewRequest(http.MethodGet, instance+"/v1/export", nil)
  52. if err != nil {
  53. fmt.Println(err)
  54. os.Exit(1)
  55. return
  56. }
  57. req.Header.Set("Content-Type", "application/json")
  58. req.Header.Set("Accept", "application/json")
  59. req.Header.Set("X-Auth-Token", token)
  60. res, err := client.Do(req)
  61. if err != nil {
  62. fmt.Println(err)
  63. os.Exit(1)
  64. return
  65. }
  66. if res.StatusCode != http.StatusOK {
  67. fmt.Println("Status code: ", res.StatusCode)
  68. os.Exit(1)
  69. return
  70. }
  71. defer res.Body.Close()
  72. ob, err := ioutil.ReadAll(res.Body)
  73. if err != nil {
  74. fmt.Println(err)
  75. os.Exit(1)
  76. return
  77. }
  78. // Unmarshal
  79. o := &opml{}
  80. err = xml.Unmarshal(ob, o)
  81. if err != nil {
  82. fmt.Println(err.Error())
  83. os.Exit(1)
  84. return
  85. }
  86. // Filter
  87. filtered := &opml{}
  88. for _, category := range categories {
  89. for _, outline := range o.Body.Outlines {
  90. if outline.Text == category {
  91. // Sort
  92. sort.Slice(outline.Outlines, func(i, j int) bool {
  93. return outline.Outlines[i].Title < outline.Outlines[j].Title
  94. })
  95. // Append
  96. filtered.Body.Outlines = append(filtered.Body.Outlines, outline)
  97. }
  98. }
  99. }
  100. // Marshal as JSON
  101. jb, err := json.MarshalIndent(filtered.Body, "", " ")
  102. if err != nil {
  103. fmt.Println(err.Error())
  104. os.Exit(1)
  105. return
  106. }
  107. // Write JSON to file
  108. err = ioutil.WriteFile(output, jb, 0644)
  109. if err != nil {
  110. fmt.Println(err.Error())
  111. os.Exit(1)
  112. return
  113. }
  114. }