浏览代码

Add more refinement options for Reddit widget

Svilen Markov 1 年之前
父节点
当前提交
840ba0f240
共有 4 个文件被更改,包括 83 次插入7 次删除
  1. 22 2
      docs/configuration.md
  2. 二进制
      docs/images/reddit-field-search.png
  3. 20 3
      internal/feed/reddit.go
  4. 41 2
      internal/widget/reddit.go

+ 22 - 2
docs/configuration.md

@@ -525,7 +525,7 @@ Display a list of posts from a specific subreddit.
 
 > [!WARNING]
 >
-> Reddit does not allow unauthorized API access from VPS IPs, if you're hosting Glance on a VPS you will get a 403 response. As a workaround you can route the traffic from Glance through a VPN.
+> Reddit does not allow unauthorized API access from VPS IPs, if you're hosting Glance on a VPS you will get a 403 response. As a workaround you can route the traffic from Glance through a VPN or your own HTTP proxy using the `request-url-template` property.
 
 Example:
 
@@ -544,6 +544,10 @@ Example:
 | collapse-after | integer | no | 5 |
 | comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
 | request-url-template | string | no |  |
+| sort-by | string | no | hot |
+| top-period | string | no | day |
+| search | string | no | |
+| extra-sort-by | string | no | |
 
 ##### `subreddit`
 The subreddit for which to fetch the posts from.
@@ -609,6 +613,22 @@ https://proxy/{REQUEST-URL}
 https://your.proxy/?url={REQUEST-URL}
 ```
 
+##### `sort-by`
+Can be used to specify the order in which the posts should get returned. Possible values are `hot`, `new`, `top` and `rising`.
+
+##### `top-perid`
+Available only when `sort-by` is set to `top`. Possible values are `hour`, `day`, `week`, `month`, `year` and `all`.
+
+##### `search`
+Keywords to search for. Searching within specific fields is also possible, **though keep in mind that Reddit may remove the ability to use any of these at any time**:
+
+![](images/reddit-field-search.png)
+
+##### `extra-sort-by`
+Can be used to specify an additional sort which will be applied on top of the already sorted posts. By default does not apply any extra sorting and the only available option is `engagement`.
+
+The `engagement` sort tries to place the posts with the most points and comments on top, also prioritizing recent over old posts.
+
 ### Weather
 Display weather information for a specific location. The data is provided by https://open-meteo.com/.
 
@@ -622,7 +642,7 @@ Example:
 
 > [!NOTE]
 >
-> US cities which have common names can have their state specified as the second parameter like such:
+> US cities which have common names can have their state specified as the second parameter as such:
 >
 > * Greenville, North Carolina, United States
 > * Greenville, South Carolina, United States

二进制
docs/images/reddit-field-search.png


+ 20 - 3
internal/feed/reddit.go

@@ -30,12 +30,29 @@ type subredditResponseJson struct {
 	} `json:"data"`
 }
 
-func FetchSubredditPosts(subreddit string, commentsUrlTemplate string, requestUrlTemplate string) (ForumPosts, error) {
-	subreddit = url.QueryEscape(subreddit)
-	requestUrl := fmt.Sprintf("https://www.reddit.com/r/%s/hot.json", subreddit)
+func FetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate, requestUrlTemplate string) (ForumPosts, error) {
+	query := url.Values{}
+	var requestUrl string
+
+	if search != "" {
+		query.Set("q", search+" subreddit:"+subreddit)
+		query.Set("sort", sort)
+	}
+
+	if sort == "top" {
+		query.Set("t", topPeriod)
+	}
+
+	if search != "" {
+		requestUrl = fmt.Sprintf("https://www.reddit.com/search.json?%s", query.Encode())
+	} else {
+		requestUrl = fmt.Sprintf("https://www.reddit.com/r/%s/%s.json?%s", subreddit, sort, query.Encode())
+	}
+
 	if requestUrlTemplate != "" {
 		requestUrl = strings.ReplaceAll(requestUrlTemplate, "{REQUEST-URL}", requestUrl)
 	}
+
 	request, err := http.NewRequest("GET", requestUrl, nil)
 
 	if err != nil {

+ 41 - 2
internal/widget/reddit.go

@@ -17,6 +17,10 @@ type Reddit struct {
 	Subreddit           string          `yaml:"subreddit"`
 	Style               string          `yaml:"style"`
 	ShowThumbnails      bool            `yaml:"show-thumbnails"`
+	SortBy              string          `yaml:"sort-by"`
+	TopPeriod           string          `yaml:"top-period"`
+	Search              string          `yaml:"search"`
+	ExtraSortBy         string          `yaml:"extra-sort-by"`
 	CommentsUrlTemplate string          `yaml:"comments-url-template"`
 	Limit               int             `yaml:"limit"`
 	CollapseAfter       int             `yaml:"collapse-after"`
@@ -36,6 +40,14 @@ func (widget *Reddit) Initialize() error {
 		widget.CollapseAfter = 5
 	}
 
+	if !isValidRedditSortType(widget.SortBy) {
+		widget.SortBy = "hot"
+	}
+
+	if !isValidRedditTopPeriod(widget.TopPeriod) {
+		widget.TopPeriod = "day"
+	}
+
 	if widget.RequestUrlTemplate != "" {
 		if !strings.Contains(widget.RequestUrlTemplate, "{REQUEST-URL}") {
 			return errors.New("no `{REQUEST-URL}` placeholder specified")
@@ -47,8 +59,32 @@ func (widget *Reddit) Initialize() error {
 	return nil
 }
 
+func isValidRedditSortType(sortBy string) bool {
+	return sortBy == "hot" ||
+		sortBy == "new" ||
+		sortBy == "top" ||
+		sortBy == "rising"
+}
+
+func isValidRedditTopPeriod(period string) bool {
+	return period == "hour" ||
+		period == "day" ||
+		period == "week" ||
+		period == "month" ||
+		period == "year" ||
+		period == "all"
+}
+
 func (widget *Reddit) Update(ctx context.Context) {
-	posts, err := feed.FetchSubredditPosts(widget.Subreddit, widget.CommentsUrlTemplate, widget.RequestUrlTemplate)
+	// TODO: refactor, use a struct to pass all of these
+	posts, err := feed.FetchSubredditPosts(
+		widget.Subreddit,
+		widget.SortBy,
+		widget.TopPeriod,
+		widget.Search,
+		widget.CommentsUrlTemplate,
+		widget.RequestUrlTemplate,
+	)
 
 	if !widget.canContinueUpdateAfterHandlingErr(err) {
 		return
@@ -58,7 +94,10 @@ func (widget *Reddit) Update(ctx context.Context) {
 		posts = posts[:widget.Limit]
 	}
 
-	posts.SortByEngagement()
+	if widget.ExtraSortBy == "engagement" {
+		posts.SortByEngagement()
+	}
+
 	widget.Posts = posts
 }