mirror of
https://github.com/glanceapp/glance.git
synced 2025-06-21 18:31:24 +02:00
Allow using alternative links for YT, HN and reddit
This commit is contained in:
parent
d5d6103327
commit
44a153d30a
@ -434,6 +434,7 @@ Preview:
|
|||||||
| ---- | ---- | -------- | ------- |
|
| ---- | ---- | -------- | ------- |
|
||||||
| channels | array | yes | |
|
| channels | array | yes | |
|
||||||
| limit | integer | no | 25 |
|
| limit | integer | no | 25 |
|
||||||
|
| video-url-template | string | no | https://www.youtube.com/watch?v={VIDEO-ID} |
|
||||||
|
|
||||||
##### `channels`
|
##### `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:
|
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`
|
##### `limit`
|
||||||
The maximum number of videos to show.
|
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
|
### Hacker News
|
||||||
Display a list of posts from [Hacker News](https://news.ycombinator.com/).
|
Display a list of posts from [Hacker News](https://news.ycombinator.com/).
|
||||||
|
|
||||||
@ -466,6 +478,19 @@ Preview:
|
|||||||
| ---- | ---- | -------- | ------- |
|
| ---- | ---- | -------- | ------- |
|
||||||
| limit | integer | no | 15 |
|
| limit | integer | no | 15 |
|
||||||
| collapse-after | integer | no | 5 |
|
| 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
|
### Reddit
|
||||||
Display a list of posts from a specific subreddit.
|
Display a list of posts from a specific subreddit.
|
||||||
@ -488,6 +513,7 @@ Example:
|
|||||||
| style | string | no | vertical-list |
|
| style | string | no | vertical-list |
|
||||||
| limit | integer | no | 15 |
|
| limit | integer | no | 15 |
|
||||||
| collapse-after | integer | no | 5 |
|
| collapse-after | integer | no | 5 |
|
||||||
|
| comments-url-template | string | no | https://www.reddit.com/{POST-PATH} |
|
||||||
|
|
||||||
##### `subreddit`
|
##### `subreddit`
|
||||||
The subreddit for which to fetch the posts from.
|
The subreddit for which to fetch the posts from.
|
||||||
@ -513,6 +539,25 @@ The maximum number of posts to show.
|
|||||||
##### `collapse-after`
|
##### `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.
|
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
|
### Weather
|
||||||
Display weather information for a specific location. The data is provided by https://open-meteo.com/.
|
Display weather information for a specific location. The data is provided by https://open-meteo.com/.
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ func getHackerNewsTopPostIds() ([]int, error) {
|
|||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
|
func getHackerNewsPostsFromIds(postIds []int, commentsUrlTemplate string) (ForumPosts, error) {
|
||||||
requests := make([]*http.Request, len(postIds))
|
requests := make([]*http.Request, len(postIds))
|
||||||
|
|
||||||
for i, id := range postIds {
|
for i, id := range postIds {
|
||||||
@ -52,9 +53,17 @@ func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
|
|||||||
continue
|
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{
|
posts = append(posts, ForumPost{
|
||||||
Title: results[i].Title,
|
Title: results[i].Title,
|
||||||
DiscussionUrl: "https://news.ycombinator.com/item?id=" + strconv.Itoa(results[i].Id),
|
DiscussionUrl: commentsUrl,
|
||||||
TargetUrl: results[i].TargetUrl,
|
TargetUrl: results[i].TargetUrl,
|
||||||
TargetUrlDomain: extractDomainFromUrl(results[i].TargetUrl),
|
TargetUrlDomain: extractDomainFromUrl(results[i].TargetUrl),
|
||||||
CommentCount: results[i].CommentCount,
|
CommentCount: results[i].CommentCount,
|
||||||
@ -74,7 +83,7 @@ func getHackerNewsPostsFromIds(postIds []int) (ForumPosts, error) {
|
|||||||
return posts, nil
|
return posts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchHackerNewsTopPosts(limit int) (ForumPosts, error) {
|
func FetchHackerNewsTopPosts(limit int, commentsUrlTemplate string) (ForumPosts, error) {
|
||||||
postIds, err := getHackerNewsTopPostIds()
|
postIds, err := getHackerNewsTopPostIds()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -85,5 +94,5 @@ func FetchHackerNewsTopPosts(limit int) (ForumPosts, error) {
|
|||||||
postIds = postIds[:limit]
|
postIds = postIds[:limit]
|
||||||
}
|
}
|
||||||
|
|
||||||
return getHackerNewsPostsFromIds(postIds)
|
return getHackerNewsPostsFromIds(postIds, commentsUrlTemplate)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"html"
|
"html"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ type subredditResponseJson struct {
|
|||||||
Data struct {
|
Data struct {
|
||||||
Children []struct {
|
Children []struct {
|
||||||
Data struct {
|
Data struct {
|
||||||
|
Id string `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Upvotes int `json:"ups"`
|
Upvotes int `json:"ups"`
|
||||||
Url string `json:"url"`
|
Url string `json:"url"`
|
||||||
@ -28,7 +30,7 @@ type subredditResponseJson struct {
|
|||||||
} `json:"data"`
|
} `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))
|
requestUrl := fmt.Sprintf("https://www.reddit.com/r/%s/hot.json", url.QueryEscape(subreddit))
|
||||||
request, err := http.NewRequest("GET", requestUrl, nil)
|
request, err := http.NewRequest("GET", requestUrl, nil)
|
||||||
|
|
||||||
@ -57,9 +59,19 @@ func FetchSubredditPosts(subreddit string) (ForumPosts, error) {
|
|||||||
continue
|
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{
|
forumPost := ForumPost{
|
||||||
Title: html.UnescapeString(post.Title),
|
Title: html.UnescapeString(post.Title),
|
||||||
DiscussionUrl: "https://www.reddit.com" + post.Permalink,
|
DiscussionUrl: commentsUrl,
|
||||||
TargetUrlDomain: post.Domain,
|
TargetUrlDomain: post.Domain,
|
||||||
CommentCount: post.CommentsCount,
|
CommentCount: post.CommentsCount,
|
||||||
Score: post.Upvotes,
|
Score: post.Upvotes,
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -38,7 +39,7 @@ func parseYoutubeFeedTime(t string) time.Time {
|
|||||||
return parsedTime
|
return parsedTime
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchYoutubeChannelUploads(channelIds []string) (Videos, error) {
|
func FetchYoutubeChannelUploads(channelIds []string, videoUrlTemplate string) (Videos, error) {
|
||||||
requests := make([]*http.Request, 0, len(channelIds))
|
requests := make([]*http.Request, 0, len(channelIds))
|
||||||
|
|
||||||
for i := range channelIds {
|
for i := range channelIds {
|
||||||
@ -75,10 +76,24 @@ func FetchYoutubeChannelUploads(channelIds []string) (Videos, error) {
|
|||||||
continue
|
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{
|
videos = append(videos, Video{
|
||||||
ThumbnailUrl: video.Group.Thumbnail.Url,
|
ThumbnailUrl: video.Group.Thumbnail.Url,
|
||||||
Title: video.Title,
|
Title: video.Title,
|
||||||
Url: video.Link.Href,
|
Url: videoUrl,
|
||||||
Author: response.Channel,
|
Author: response.Channel,
|
||||||
AuthorUrl: response.ChannelLink.Href + "/videos",
|
AuthorUrl: response.ChannelLink.Href + "/videos",
|
||||||
TimePosted: parseYoutubeFeedTime(video.Published),
|
TimePosted: parseYoutubeFeedTime(video.Published),
|
||||||
|
@ -10,10 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HackerNews struct {
|
type HackerNews struct {
|
||||||
widgetBase `yaml:",inline"`
|
widgetBase `yaml:",inline"`
|
||||||
Posts feed.ForumPosts `yaml:"-"`
|
Posts feed.ForumPosts `yaml:"-"`
|
||||||
Limit int `yaml:"limit"`
|
Limit int `yaml:"limit"`
|
||||||
CollapseAfter int `yaml:"collapse-after"`
|
CollapseAfter int `yaml:"collapse-after"`
|
||||||
|
CommentsUrlTemplate string `yaml:"comments-url-template"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (widget *HackerNews) Initialize() error {
|
func (widget *HackerNews) Initialize() error {
|
||||||
@ -31,7 +32,7 @@ func (widget *HackerNews) Initialize() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (widget *HackerNews) Update(ctx context.Context) {
|
func (widget *HackerNews) Update(ctx context.Context) {
|
||||||
posts, err := feed.FetchHackerNewsTopPosts(40)
|
posts, err := feed.FetchHackerNewsTopPosts(40, widget.CommentsUrlTemplate)
|
||||||
|
|
||||||
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||||
return
|
return
|
||||||
|
@ -11,12 +11,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Reddit struct {
|
type Reddit struct {
|
||||||
widgetBase `yaml:",inline"`
|
widgetBase `yaml:",inline"`
|
||||||
Posts feed.ForumPosts `yaml:"-"`
|
Posts feed.ForumPosts `yaml:"-"`
|
||||||
Subreddit string `yaml:"subreddit"`
|
Subreddit string `yaml:"subreddit"`
|
||||||
Style string `yaml:"style"`
|
Style string `yaml:"style"`
|
||||||
Limit int `yaml:"limit"`
|
CommentsUrlTemplate string `yaml:"comments-url-template"`
|
||||||
CollapseAfter int `yaml:"collapse-after"`
|
Limit int `yaml:"limit"`
|
||||||
|
CollapseAfter int `yaml:"collapse-after"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Reddit) Initialize() error {
|
func (widget *Reddit) Initialize() error {
|
||||||
@ -38,7 +39,7 @@ func (widget *Reddit) Initialize() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Reddit) Update(ctx context.Context) {
|
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) {
|
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||||
return
|
return
|
||||||
|
@ -10,10 +10,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Videos struct {
|
type Videos struct {
|
||||||
widgetBase `yaml:",inline"`
|
widgetBase `yaml:",inline"`
|
||||||
Videos feed.Videos `yaml:"-"`
|
Videos feed.Videos `yaml:"-"`
|
||||||
Channels []string `yaml:"channels"`
|
VideoUrlTemplate string `yaml:"video-url-template"`
|
||||||
Limit int `yaml:"limit"`
|
Channels []string `yaml:"channels"`
|
||||||
|
Limit int `yaml:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Videos) Initialize() error {
|
func (widget *Videos) Initialize() error {
|
||||||
@ -27,7 +28,7 @@ func (widget *Videos) Initialize() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Videos) Update(ctx context.Context) {
|
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) {
|
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user