Allow using a standard HTTP proxy in reddit widget

This commit is contained in:
Svilen Markov 2025-01-06 20:40:46 +00:00
parent abbb4950a5
commit 108c83588c
3 changed files with 105 additions and 16 deletions

View file

@ -746,6 +746,7 @@ Example:
| collapse-after | integer | no | 5 |
| comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
| request-url-template | string | no | |
| proxy | string or multiple parameters | no | |
| sort-by | string | no | hot |
| top-period | string | no | day |
| search | string | no | |
@ -807,7 +808,7 @@ r/selfhosted/comments/bsp01i/welcome_to_rselfhosted_please_read_this_first/
`{SUBREDDIT}` - the subreddit name
##### `request-url-template`
A custom request url that will be used to fetch the data instead. This is useful when you're hosting Glance on a VPS and Reddit is blocking the requests, and you want to route it through an HTTP proxy.
A custom request URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to route them through a proxy that accepts the URL as either a part of the path or a query parameter.
Placeholders:
@ -818,6 +819,29 @@ https://proxy/{REQUEST-URL}
https://your.proxy/?url={REQUEST-URL}
```
##### `proxy`
A custom HTTP/HTTPS proxy URL that will be used to fetch the data. This is useful when you're hosting Glance on a VPS where Reddit is blocking the requests and you want to bypass the restriction by routing the requests through a proxy. Example:
```
proxy: http://user:pass@proxy.com:8080
proxy: https://user:pass@proxy.com:443
```
Alternatively, you can specify the proxy URL as well as additional options by using multiple parameters:
```yaml
proxy:
url: http://proxy.com:8080
allow-insecure: true
timeout: 10s
```
###### `allow-insecure`
When set to `true`, allows the use of insecure connections such as when the proxy has a self-signed certificate.
###### `timeout`
The maximum time to wait for a response from the proxy. The value is a string and must be a number followed by one of s, m, h, d. Example: `10s` for 10 seconds, `1m` for 1 minute, etc
##### `sort-by`
Can be used to specify the order in which the posts should get returned. Possible values are `hot`, `new`, `top` and `rising`.

View file

@ -1,7 +1,10 @@
package glance
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
@ -169,3 +172,50 @@ func (i *customIconField) UnmarshalYAML(node *yaml.Node) error {
*i = newCustomIconField(value)
return nil
}
type proxyOptionsField struct {
URL string `yaml:"url"`
AllowInsecure bool `yaml:"allow-insecure"`
Timeout durationField `yaml:"timeout"`
client *http.Client `yaml:"-"`
}
func (p *proxyOptionsField) UnmarshalYAML(node *yaml.Node) error {
type proxyOptionsFieldAlias proxyOptionsField
alias := (*proxyOptionsFieldAlias)(p)
var proxyURL string
if err := node.Decode(&proxyURL); err != nil {
if err := node.Decode(alias); err != nil {
return err
}
}
if proxyURL == "" && p.URL == "" {
return nil
}
if p.URL != "" {
proxyURL = p.URL
}
parsedUrl, err := url.Parse(proxyURL)
if err != nil {
return fmt.Errorf("parsing proxy URL: %v", err)
}
var timeout = defaultClientTimeout
if p.Timeout > 0 {
timeout = time.Duration(p.Timeout)
}
p.client = &http.Client{
Timeout: timeout,
Transport: &http.Transport{
Proxy: http.ProxyURL(parsedUrl),
TLSClientConfig: &tls.Config{InsecureSkipVerify: p.AllowInsecure},
},
}
return nil
}

View file

@ -19,19 +19,20 @@ var (
type redditWidget struct {
widgetBase `yaml:",inline"`
Posts forumPostList `yaml:"-"`
Subreddit string `yaml:"subreddit"`
Style string `yaml:"style"`
ShowThumbnails bool `yaml:"show-thumbnails"`
ShowFlairs bool `yaml:"show-flairs"`
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"`
RequestUrlTemplate string `yaml:"request-url-template"`
Posts forumPostList `yaml:"-"`
Subreddit string `yaml:"subreddit"`
Proxy proxyOptionsField `yaml:"proxy"`
Style string `yaml:"style"`
ShowThumbnails bool `yaml:"show-thumbnails"`
ShowFlairs bool `yaml:"show-flairs"`
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"`
RequestUrlTemplate string `yaml:"request-url-template"`
}
func (widget *redditWidget) initialize() error {
@ -94,6 +95,7 @@ func (widget *redditWidget) update(ctx context.Context) {
widget.Search,
widget.CommentsUrlTemplate,
widget.RequestUrlTemplate,
widget.Proxy.client,
widget.ShowFlairs,
)
@ -161,7 +163,16 @@ func templateRedditCommentsURL(template, subreddit, postId, postPath string) str
return template
}
func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate, requestUrlTemplate string, showFlairs bool) (forumPostList, error) {
func fetchSubredditPosts(
subreddit,
sort,
topPeriod,
search,
commentsUrlTemplate,
requestUrlTemplate string,
proxyClient *http.Client,
showFlairs bool,
) (forumPostList, error) {
query := url.Values{}
var requestUrl string
@ -180,8 +191,12 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate
requestUrl = fmt.Sprintf("https://www.reddit.com/r/%s/%s.json?%s", subreddit, sort, query.Encode())
}
var client requestDoer = defaultHTTPClient
if requestUrlTemplate != "" {
requestUrl = strings.ReplaceAll(requestUrlTemplate, "{REQUEST-URL}", requestUrl)
} else if proxyClient != nil {
client = proxyClient
}
request, err := http.NewRequest("GET", requestUrl, nil)
@ -191,7 +206,7 @@ func fetchSubredditPosts(subreddit, sort, topPeriod, search, commentsUrlTemplate
// Required to increase rate limit, otherwise Reddit randomly returns 429 even after just 2 requests
setBrowserUserAgentHeader(request)
responseJson, err := decodeJsonFromRequest[subredditResponseJson](defaultHTTPClient, request)
responseJson, err := decodeJsonFromRequest[subredditResponseJson](client, request)
if err != nil {
return nil, err
}