Merge 12eb087531
into f8816ff227
This commit is contained in:
commit
ce699c8069
9 changed files with 167 additions and 1 deletions
|
@ -21,6 +21,7 @@
|
|||
- [Twitch Channels](#twitch-channels)
|
||||
- [Twitch Top Games](#twitch-top-games)
|
||||
- [iframe](#iframe)
|
||||
- [bilibili](#bilibili)
|
||||
|
||||
## Intro
|
||||
Configuration is done via a single YAML file and a server restart is required in order for any changes to take effect. Trying to start the server with an invalid config file will result in an error.
|
||||
|
@ -1132,3 +1133,20 @@ The source of the iframe.
|
|||
|
||||
##### `height`
|
||||
The height of the iframe. The minimum allowed height is 50.
|
||||
|
||||
## bilibili
|
||||
Display a list of the latest videos from specific bilibili channels.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
- type: bilibili
|
||||
uidList:
|
||||
- 50329118 # LOL
|
||||
- 578227337
|
||||
```
|
||||
|
||||
Preview:
|
||||

|
||||
|
||||
|
||||
|
|
BIN
docs/images/videos-widget-preview-bilibili.png
Normal file
BIN
docs/images/videos-widget-preview-bilibili.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
3
go.mod
3
go.mod
|
@ -4,6 +4,7 @@ go 1.22.0
|
|||
|
||||
require (
|
||||
github.com/mmcdole/gofeed v1.3.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
golang.org/x/text v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
@ -11,9 +12,11 @@ require (
|
|||
require (
|
||||
github.com/PuerkitoBio/goquery v1.9.1 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mmcdole/goxpp v1.1.1 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
)
|
||||
|
|
5
go.sum
5
go.sum
|
@ -20,7 +20,11 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
|||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
|
@ -63,5 +67,6 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{{ define "video-card-contents" }}
|
||||
<img class="video-thumbnail thumbnail" loading="lazy" src="{{ .ThumbnailUrl }}" alt="">
|
||||
<img referrerpolicy="no-referrer" class="video-thumbnail thumbnail" loading="lazy" src="{{ .ThumbnailUrl }}" alt="">
|
||||
<div class="margin-top-10 margin-bottom-widget flex flex-column grow padding-inline-widget">
|
||||
<a class="video-title color-primary-if-not-visited" href="{{ .Url }}" target="_blank" rel="noreferrer" title="{{ .Title }}">{{ .Title }}</a>
|
||||
<ul class="list-horizontal-text flex-nowrap margin-top-7">
|
||||
|
|
76
internal/feed/bilibili.go
Normal file
76
internal/feed/bilibili.go
Normal file
|
@ -0,0 +1,76 @@
|
|||
package feed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type bilibiliSpaceResponseJson struct {
|
||||
Data struct {
|
||||
Item []struct {
|
||||
Title string `json:"title"`
|
||||
Cover string `json:"cover"`
|
||||
Ctime int64 `json:"ctime"`
|
||||
Author string `json:"author"`
|
||||
Bvid string `json:"bvid"`
|
||||
} `json:"item"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func FetchBilibiliUploads(uidList []int) (Videos, error) {
|
||||
requests := make([]*http.Request, 0, len(uidList))
|
||||
u := "https://app.bilibili.com/x/v2/space/archive/cursor?vmid="
|
||||
for i := range uidList {
|
||||
request, _ := http.NewRequest("GET", u+strconv.Itoa(uidList[i]), nil)
|
||||
request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
|
||||
request.Header.Set("Referer", "https://www.bilibili.com/")
|
||||
|
||||
requests = append(requests, request)
|
||||
}
|
||||
|
||||
job := newJob(decodeJsonFromRequestTask[bilibiliSpaceResponseJson](defaultClient), requests).withWorkers(30)
|
||||
|
||||
responses, errs, err := workerPoolDo(job)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrNoContent, err)
|
||||
}
|
||||
|
||||
videos := make(Videos, 0, len(uidList)*15)
|
||||
var failed int
|
||||
for i := range responses {
|
||||
if errs[i] != nil {
|
||||
failed++
|
||||
slog.Error("Failed to fetch bilibili feed", "uid", uidList[i], "error", errs[i])
|
||||
continue
|
||||
}
|
||||
response := responses[i]
|
||||
for j := range response.Data.Item {
|
||||
video := &response.Data.Item[j]
|
||||
videoUrl := `https://www.bilibili.com/video/` + video.Bvid
|
||||
videos = append(videos, Video{
|
||||
ThumbnailUrl: video.Cover,
|
||||
Title: video.Title,
|
||||
Url: strings.ReplaceAll(videoUrl, "http://", "https://"),
|
||||
Author: video.Author,
|
||||
AuthorUrl: `https://space.bilibili.com/` + strconv.Itoa(uidList[i]),
|
||||
TimePosted: time.Unix(video.Ctime, 0),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(videos) == 0 {
|
||||
return nil, ErrNoContent
|
||||
}
|
||||
|
||||
videos.SortByNewest()
|
||||
|
||||
if failed > 0 {
|
||||
return videos, fmt.Errorf("%w: missing videos from %d up", ErrPartialContent, failed)
|
||||
}
|
||||
|
||||
return videos, nil
|
||||
}
|
12
internal/feed/bilibili_test.go
Normal file
12
internal/feed/bilibili_test.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package feed
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFetchBilibiliUploads(t *testing.T) {
|
||||
videos, err := FetchBilibiliUploads([]int{50329118})
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, len(videos) > 0)
|
||||
}
|
50
internal/widget/bilibili.go
Normal file
50
internal/widget/bilibili.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package widget
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/glanceapp/glance/internal/assets"
|
||||
"github.com/glanceapp/glance/internal/feed"
|
||||
"html/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Bilibili struct {
|
||||
widgetBase `yaml:",inline"`
|
||||
Videos feed.Videos `yaml:"-"`
|
||||
Style string `yaml:"style"`
|
||||
UidList []int `yaml:"uidList"`
|
||||
Limit int `yaml:"limit"`
|
||||
}
|
||||
|
||||
var _ Widget = (*Bilibili)(nil)
|
||||
|
||||
func (widget *Bilibili) Initialize() error {
|
||||
widget.withTitle("Bilibili").withCacheDuration(time.Hour)
|
||||
|
||||
if widget.Limit <= 0 {
|
||||
widget.Limit = 25
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (widget *Bilibili) Update(ctx context.Context) {
|
||||
videos, err := feed.FetchBilibiliUploads(widget.UidList)
|
||||
|
||||
if !widget.canContinueUpdateAfterHandlingErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(videos) > widget.Limit {
|
||||
videos = videos[:widget.Limit]
|
||||
}
|
||||
|
||||
widget.Videos = videos
|
||||
}
|
||||
|
||||
func (widget *Bilibili) Render() template.HTML {
|
||||
if widget.Style == "grid-cards" {
|
||||
return widget.render(widget, assets.VideosGridTemplate)
|
||||
}
|
||||
|
||||
return widget.render(widget, assets.VideosTemplate)
|
||||
}
|
|
@ -31,6 +31,8 @@ func New(widgetType string) (Widget, error) {
|
|||
return &Releases{}, nil
|
||||
case "videos":
|
||||
return &Videos{}, nil
|
||||
case "bilibili":
|
||||
return &Bilibili{}, nil
|
||||
case "stocks":
|
||||
return &Stocks{}, nil
|
||||
case "reddit":
|
||||
|
|
Loading…
Add table
Reference in a new issue