reddit.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package widget
  2. import (
  3. "context"
  4. "errors"
  5. "html/template"
  6. "strings"
  7. "time"
  8. "github.com/glanceapp/glance/internal/assets"
  9. "github.com/glanceapp/glance/internal/feed"
  10. )
  11. type Reddit struct {
  12. widgetBase `yaml:",inline"`
  13. Posts feed.ForumPosts `yaml:"-"`
  14. Subreddit string `yaml:"subreddit"`
  15. Style string `yaml:"style"`
  16. ShowThumbnails bool `yaml:"show-thumbnails"`
  17. SortBy string `yaml:"sort-by"`
  18. TopPeriod string `yaml:"top-period"`
  19. Search string `yaml:"search"`
  20. ExtraSortBy string `yaml:"extra-sort-by"`
  21. CommentsUrlTemplate string `yaml:"comments-url-template"`
  22. Limit int `yaml:"limit"`
  23. CollapseAfter int `yaml:"collapse-after"`
  24. RequestUrlTemplate string `yaml:"request-url-template"`
  25. }
  26. func (widget *Reddit) Initialize() error {
  27. if widget.Subreddit == "" {
  28. return errors.New("no subreddit specified")
  29. }
  30. if widget.Limit <= 0 {
  31. widget.Limit = 15
  32. }
  33. if widget.CollapseAfter == 0 || widget.CollapseAfter < -1 {
  34. widget.CollapseAfter = 5
  35. }
  36. if !isValidRedditSortType(widget.SortBy) {
  37. widget.SortBy = "hot"
  38. }
  39. if !isValidRedditTopPeriod(widget.TopPeriod) {
  40. widget.TopPeriod = "day"
  41. }
  42. if widget.RequestUrlTemplate != "" {
  43. if !strings.Contains(widget.RequestUrlTemplate, "{REQUEST-URL}") {
  44. return errors.New("no `{REQUEST-URL}` placeholder specified")
  45. }
  46. }
  47. widget.
  48. withTitle("/r/" + widget.Subreddit).
  49. withTitleURL("https://www.reddit.com/r/" + widget.Subreddit + "/").
  50. withCacheDuration(30 * time.Minute)
  51. return nil
  52. }
  53. func isValidRedditSortType(sortBy string) bool {
  54. return sortBy == "hot" ||
  55. sortBy == "new" ||
  56. sortBy == "top" ||
  57. sortBy == "rising"
  58. }
  59. func isValidRedditTopPeriod(period string) bool {
  60. return period == "hour" ||
  61. period == "day" ||
  62. period == "week" ||
  63. period == "month" ||
  64. period == "year" ||
  65. period == "all"
  66. }
  67. func (widget *Reddit) Update(ctx context.Context) {
  68. // TODO: refactor, use a struct to pass all of these
  69. posts, err := feed.FetchSubredditPosts(
  70. widget.Subreddit,
  71. widget.SortBy,
  72. widget.TopPeriod,
  73. widget.Search,
  74. widget.CommentsUrlTemplate,
  75. widget.RequestUrlTemplate,
  76. )
  77. if !widget.canContinueUpdateAfterHandlingErr(err) {
  78. return
  79. }
  80. if len(posts) > widget.Limit {
  81. posts = posts[:widget.Limit]
  82. }
  83. if widget.ExtraSortBy == "engagement" {
  84. posts.CalculateEngagement()
  85. posts.SortByEngagement()
  86. }
  87. widget.Posts = posts
  88. }
  89. func (widget *Reddit) Render() template.HTML {
  90. if widget.Style == "horizontal-cards" {
  91. return widget.render(widget, assets.RedditCardsHorizontalTemplate)
  92. }
  93. if widget.Style == "vertical-cards" {
  94. return widget.render(widget, assets.RedditCardsVerticalTemplate)
  95. }
  96. return widget.render(widget, assets.ForumPostsTemplate)
  97. }