diff --git a/docs/configuration.md b/docs/configuration.md index 70e76de..a2170cd 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,6 +34,8 @@ - [DNS Stats](#dns-stats) - [Server Stats](#server-stats) - [Repository](#repository) + + - [Trending Repositories](#trending-repositories) - [Bookmarks](#bookmarks) - [Calendar](#calendar) - [Calendar (legacy)](#calendar-legacy) @@ -907,7 +909,7 @@ https://www.youtube.com...&list={ID}&... The maximum number of videos to show. ##### `sort-by` -Used to specify the order in which the videos should get returned. Possible values are `none`, `updated`, and `posted`. +Used to specify the order in which the videos should get returned. Possible values are `none`, `updated`, and `posted`. Default value is `posted`. ##### `collapse-after` diff --git a/docs/images/trending-repositories-widget-preview.png b/docs/images/trending-repositories-widget-preview.png new file mode 100644 index 0000000..3760b83 Binary files /dev/null and b/docs/images/trending-repositories-widget-preview.png differ diff --git a/go.mod b/go.mod index f0d15ee..d59c9e6 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/shirou/gopsutil/v4 v4.25.5 github.com/tidwall/gjson v1.18.0 golang.org/x/crypto v0.39.0 + golang.org/x/net v0.41.0 golang.org/x/text v0.26.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -28,6 +29,5 @@ require ( github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect ) diff --git a/go.sum b/go.sum index ee3bde9..56ae190 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/shirou/gopsutil/v4 v4.25.4 h1:cdtFO363VEOOFrUCjZRh4XVJkb548lyF0q0uTeMqYPw= -github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -61,8 +59,6 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -79,8 +75,6 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -124,8 +118,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/glance/searchable-node.go b/internal/glance/searchable-node.go new file mode 100644 index 0000000..83f002a --- /dev/null +++ b/internal/glance/searchable-node.go @@ -0,0 +1,161 @@ +package glance + +import ( + "strings" + + "golang.org/x/net/html" +) + +type searchableNode html.Node + +func (n *searchableNode) findFirst(tag string, attrs ...string) *searchableNode { + if tag == "" || n == nil { + return nil + } + + if len(attrs)%2 != 0 { + panic("attributes must be in key-value pairs") + } + + if n.matches(tag, attrs...) { + return n + } + + for child := n.FirstChild; child != nil; child = child.NextSibling { + if child.Type != html.ElementNode { + continue + } + + if found := (*searchableNode)(child).findFirst(tag, attrs...); found != nil { + return found + } + } + + return nil +} + +func (n *searchableNode) nthChild(index int) *searchableNode { + if n == nil || index < 0 { + return nil + } + + if index == 0 { + return n + } + + count := 0 + for child := n.FirstChild; child != nil; child = child.NextSibling { + if child.Type != html.ElementNode { + continue + } + + count++ + if count == index { + return (*searchableNode)(child) + } + } + + return nil +} + +func (n *searchableNode) findFirstChild(tag string, attrs ...string) *searchableNode { + if tag == "" || n == nil { + return nil + } + + if len(attrs)%2 != 0 { + panic("attributes must be in key-value pairs") + } + + for child := n.FirstChild; child != nil; child = child.NextSibling { + if child.Type != html.ElementNode { + continue + } + + if child.Type == html.ElementNode && (*searchableNode)(child).matches(tag, attrs...) { + return (*searchableNode)(child) + } + } + + return nil +} + +func (n *searchableNode) findAll(tag string, attrs ...string) []*searchableNode { + if tag == "" || n == nil { + return nil + } + + if len(attrs)%2 != 0 { + panic("attributes must be in key-value pairs") + } + + var results []*searchableNode + + if n.matches(tag, attrs...) { + results = append(results, n) + } + + for child := n.FirstChild; child != nil; child = child.NextSibling { + if child.Type != html.ElementNode { + continue + } + + results = append(results, (*searchableNode)(child).findAll(tag, attrs...)...) + } + + return results +} + +func (n *searchableNode) matches(tag string, attrs ...string) bool { + if tag == "" || n == nil { + return false + } + + if len(attrs)%2 != 0 { + panic("attributes must be in key-value pairs") + } + + if n.Data != tag { + return false + } + + for i := 0; i < len(attrs); i += 2 { + key := attrs[i] + value := attrs[i+1] + found := false + for _, attr := range n.Attr { + if attr.Key == key && attr.Val == value { + found = true + break + } + } + if !found { + return false + } + } + + return true +} + +func (n *searchableNode) text() string { + if n == nil { + return "" + } + + if n.Type == html.TextNode { + return strings.TrimSpace(n.Data) + } + + var builder strings.Builder + + for child := n.FirstChild; child != nil; child = child.NextSibling { + switch child.Type { + case html.TextNode: + builder.WriteString(strings.TrimSpace(child.Data)) + case html.ElementNode: + builder.WriteString((*searchableNode)(child).text()) + } + } + + return builder.String() +} diff --git a/internal/glance/templates/trending-repositories.html b/internal/glance/templates/trending-repositories.html new file mode 100644 index 0000000..e9cac4e --- /dev/null +++ b/internal/glance/templates/trending-repositories.html @@ -0,0 +1,22 @@ +{{ template "widget-base.html" . }} + +{{ define "widget-content" }} +
{{ .Description }}
+ {{ end }} +No repositories found.
+ {{ end }} +