Allow using alternative links for YT, HN and reddit

This commit is contained in:
Svilen Markov 2024-05-01 19:08:25 +01:00
parent d5d6103327
commit 44a153d30a
7 changed files with 109 additions and 25 deletions

View File

@ -434,6 +434,7 @@ Preview:
| ---- | ---- | -------- | ------- |
| channels | array | yes | |
| limit | integer | no | 25 |
| video-url-template | string | no | https://www.youtube.com/watch?v={VIDEO-ID} |
##### `channels`
A list of channel IDs. One way of getting the ID of a channel is going to the channel's page and clicking on its description:
@ -447,6 +448,17 @@ Then scroll down and click on "Share channel", then "Copy channel ID":
##### `limit`
The maximum number of videos to show.
##### `video-url-template`
Used to replace the default link for videos. Useful when you're running your own YouTube front-end. Example:
```yaml
video-url-template: https://invidious.your-domain.com/watch?v={VIDEO-ID}
```
Placeholders:
`{VIDEO-ID}` - the ID of the video
### Hacker News
Display a list of posts from [Hacker News](https://news.ycombinator.com/).
@ -466,6 +478,19 @@ Preview:
| ---- | ---- | -------- | ------- |
| limit | integer | no | 15 |
| collapse-after | integer | no | 5 |
| comments-url-template | string | no | https://news.ycombinator.com/item?id={POST-ID} |
##### `comments-url-template`
Used to replace the default link for post comments. Useful if you want to use an alternative front-end. Example:
```yaml
comments-url-template: https://www.hckrnws.com/stories/{POST-PATH}
```
Placeholders:
`{POST-ID}` - the ID of the post
### Reddit
Display a list of posts from a specific subreddit.
@ -488,6 +513,7 @@ Example:
| style | string | no | vertical-list |
| limit | integer | no | 15 |
| collapse-after | integer | no | 5 |
| comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
##### `subreddit`
The subreddit for which to fetch the posts from.
@ -513,6 +539,25 @@ The maximum number of posts to show.
##### `collapse-after`
How many posts are visible before the "SHOW MORE" button appears. Set to `-1` to never collapse. Not available when using the `vertical-cards` and `horizontal-cards` styles.
##### `comments-url-template`
Used to replace the default link for post comments. Useful if you want to use the old Reddit design or any other 3rd party front-end. Example:
```yaml
comments-url-template: https://old.reddit.com/{POST-PATH}
```
Placeholders:
`{POST-PATH}` - the full path to the post, such as:
```
r/selfhosted/comments/bsp01i/welcome_to_rselfhosted_please_read_this_first/
```
`{POST-ID}` - the ID that comes after `/comments/`
`{SUBREDDIT}` - the subreddit name
### Weather
Display weather information for a specific location. The data is provided by https://open-meteo.com/.

View File

@ -5,6 +5,7 @@ import (
"log/slog"
"net/http"
"strconv"
"strings"
"time"
)
@ -28,7 +29,7 @@ func getHackerNewsTopPostIds() ([]int, error) {
return response, nil
}
func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
func getHackerNewsPostsFromIds(postIds []int, commentsUrlTemplate string) (ForumPosts, error) {
requests := make([]*http.Request, len(postIds))
for i, id := range postIds {
@ -52,9 +53,17 @@ func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
continue
}
var commentsUrl string
if commentsUrlTemplate == "" {
commentsUrl = "https://news.ycombinator.com/item?id=" + strconv.Itoa(results[i].Id)
} else {
commentsUrl = strings.ReplaceAll(commentsUrlTemplate, "{POST-ID}", strconv.Itoa(results[i].Id))
}
posts = append(posts, ForumPost{
Title: results[i].Title,
DiscussionUrl: "https://news.ycombinator.com/item?id=" + strconv.Itoa(results[i].Id),
DiscussionUrl: commentsUrl,
TargetUrl: results[i].TargetUrl,
TargetUrlDomain: extractDomainFromUrl(results[i].TargetUrl),
CommentCount: results[i].CommentCount,
@ -74,7 +83,7 @@ func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
return posts, nil
}
func FetchHackerNewsTopPosts(limit int) (ForumPosts, error) {
func FetchHackerNewsTopPosts(limit int, commentsUrlTemplate string) (ForumPosts, error) {
postIds, err := getHackerNewsTopPostIds()
if err != nil {
@ -85,5 +94,5 @@ func FetchHackerNewsTopPosts(limit int) (ForumPosts, error) {
postIds = postIds[:limit]
}
return getHackerNewsPostsFromIds(postIds)
return getHackerNewsPostsFromIds(postIds, commentsUrlTemplate)
}

View File

@ -5,6 +5,7 @@ import (
"html"
"net/http"
"net/url"
"strings"
"time"
)
@ -12,6 +13,7 @@ type subredditResponseJson struct {
Data struct {
Children []struct {
Data struct {
Id string `json:"id"`
Title string `json:"title"`
Upvotes int `json:"ups"`
Url string `json:"url"`
@ -28,7 +30,7 @@ type subredditResponseJson struct {
} `json:"data"`
}
func FetchSubredditPosts(subreddit string) (ForumPosts, error) {
func FetchSubredditPosts(subreddit string, commentsUrlTemplate string) (ForumPosts, error) {
requestUrl := fmt.Sprintf("https://www.reddit.com/r/%s/hot.json", url.QueryEscape(subreddit))
request, err := http.NewRequest("GET", requestUrl, nil)
@ -57,9 +59,19 @@ func FetchSubredditPosts(subreddit string) (ForumPosts, error) {
continue
}
var commentsUrl string
if commentsUrlTemplate == "" {
commentsUrl = "https://www.reddit.com" + post.Permalink
} else {
commentsUrl = strings.ReplaceAll(commentsUrlTemplate, "{SUBREDDIT}", subreddit)
commentsUrl = strings.ReplaceAll(commentsUrl, "{POST-ID}", post.Id)
commentsUrl = strings.ReplaceAll(commentsUrl, "{POST-PATH}", strings.TrimLeft(post.Permalink, "/"))
}
forumPost := ForumPost{
Title: html.UnescapeString(post.Title),
DiscussionUrl: "https://www.reddit.com" + post.Permalink,
DiscussionUrl: commentsUrl,
TargetUrlDomain: post.Domain,
CommentCount: post.CommentsCount,
Score: post.Upvotes,

View File

@ -4,6 +4,7 @@ import (
"fmt"
"log/slog"
"net/http"
"net/url"
"strings"
"time"
)
@ -38,7 +39,7 @@ func parseYoutubeFeedTime(t string) time.Time {
return parsedTime
}
func FetchYoutubeChannelUploads(channelIds []string) (Videos, error) {
func FetchYoutubeChannelUploads(channelIds []string, videoUrlTemplate string) (Videos, error) {
requests := make([]*http.Request, 0, len(channelIds))
for i := range channelIds {
@ -75,10 +76,24 @@ func FetchYoutubeChannelUploads(channelIds []string) (Videos, error) {
continue
}
var videoUrl string
if videoUrlTemplate == "" {
videoUrl = video.Link.Href
} else {
parsedUrl, err := url.Parse(video.Link.Href)
if err == nil {
videoUrl = strings.ReplaceAll(videoUrlTemplate, "{VIDEO-ID}", parsedUrl.Query().Get("v"))
} else {
videoUrl = "#"
}
}
videos = append(videos, Video{
ThumbnailUrl: video.Group.Thumbnail.Url,
Title: video.Title,
Url: video.Link.Href,
Url: videoUrl,
Author: response.Channel,
AuthorUrl: response.ChannelLink.Href + "/videos",
TimePosted: parseYoutubeFeedTime(video.Published),

View File

@ -10,10 +10,11 @@ import (
)
type HackerNews struct {
widgetBase `yaml:",inline"`
Posts feed.ForumPosts `yaml:"-"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
widgetBase `yaml:",inline"`
Posts feed.ForumPosts `yaml:"-"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
CommentsUrlTemplate string `yaml:"comments-url-template"`
}
func (widget *HackerNews) Initialize() error {
@ -31,7 +32,7 @@ func (widget *HackerNews) Initialize() error {
}
func (widget *HackerNews) Update(ctx context.Context) {
posts, err := feed.FetchHackerNewsTopPosts(40)
posts, err := feed.FetchHackerNewsTopPosts(40, widget.CommentsUrlTemplate)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return

View File

@ -11,12 +11,13 @@ import (
)
type Reddit struct {
widgetBase `yaml:",inline"`
Posts feed.ForumPosts `yaml:"-"`
Subreddit string `yaml:"subreddit"`
Style string `yaml:"style"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
widgetBase `yaml:",inline"`
Posts feed.ForumPosts `yaml:"-"`
Subreddit string `yaml:"subreddit"`
Style string `yaml:"style"`
CommentsUrlTemplate string `yaml:"comments-url-template"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
}
func (widget *Reddit) Initialize() error {
@ -38,7 +39,7 @@ func (widget *Reddit) Initialize() error {
}
func (widget *Reddit) Update(ctx context.Context) {
posts, err := feed.FetchSubredditPosts(widget.Subreddit)
posts, err := feed.FetchSubredditPosts(widget.Subreddit, widget.CommentsUrlTemplate)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return

View File

@ -10,10 +10,11 @@ import (
)
type Videos struct {
widgetBase `yaml:",inline"`
Videos feed.Videos `yaml:"-"`
Channels []string `yaml:"channels"`
Limit int `yaml:"limit"`
widgetBase `yaml:",inline"`
Videos feed.Videos `yaml:"-"`
VideoUrlTemplate string `yaml:"video-url-template"`
Channels []string `yaml:"channels"`
Limit int `yaml:"limit"`
}
func (widget *Videos) Initialize() error {
@ -27,7 +28,7 @@ func (widget *Videos) Initialize() error {
}
func (widget *Videos) Update(ctx context.Context) {
videos, err := feed.FetchYoutubeChannelUploads(widget.Channels)
videos, err := feed.FetchYoutubeChannelUploads(widget.Channels, widget.VideoUrlTemplate)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return