parent
8ec7b3fb52
commit
a54e766bd3
|
@ -0,0 +1,2 @@
|
|||
/trending
|
||||
/trending.exe
|
|
@ -0,0 +1,65 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Languages []struct {
|
||||
Name string `yaml:"name"`
|
||||
Timeframes []string `yaml:"timeframes"`
|
||||
} `yaml:"languages"`
|
||||
}
|
||||
|
||||
func loadConfig() (*config, error) {
|
||||
cfgPath, err := xdg.ConfigFile("trending/config.yaml")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get config file path: %w", err)
|
||||
}
|
||||
fi, err := os.Open(cfgPath)
|
||||
if err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, fmt.Errorf("could not open config file: %w", err)
|
||||
}
|
||||
if err := createDefaultConfig(cfgPath); err != nil {
|
||||
return nil, fmt.Errorf("could not create default config: %w", err)
|
||||
}
|
||||
return loadConfig()
|
||||
}
|
||||
defer fi.Close()
|
||||
|
||||
var cfg config
|
||||
if err := yaml.NewDecoder(fi).Decode(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("could not decode config: %w", err)
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func createDefaultConfig(cfgPath string) error {
|
||||
fi, err := os.Create(cfgPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fi.Close()
|
||||
_, err = fi.Write(defaultConfig)
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultConfig = []byte(`languages:
|
||||
- name: go
|
||||
timeframes:
|
||||
- daily
|
||||
- weekly
|
||||
- monthly
|
||||
- name: rust
|
||||
timeframes:
|
||||
- daily
|
||||
- weekly
|
||||
- monthly
|
||||
`)
|
2
go.mod
2
go.mod
|
@ -4,8 +4,10 @@ go 1.19
|
|||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.8.0
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/caarlos0/log v0.1.10
|
||||
github.com/charmbracelet/lipgloss v0.6.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
15
go.sum
15
go.sum
|
@ -1,5 +1,7 @@
|
|||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
|
||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
|
||||
|
@ -9,6 +11,8 @@ github.com/caarlos0/log v0.1.10 h1:kHKiXTKEeK019o7QQWXRbHVKFrYYljxuQ7vF2taEA3M=
|
|||
github.com/caarlos0/log v0.1.10/go.mod h1:BLxpdZKXvWBjB6fshua4c8d7ApdYjypEDok6ibt+pXk=
|
||||
github.com/charmbracelet/lipgloss v0.6.0 h1:1StyZB9vBSOyuZxQUcUwGr17JmojPNm87inij9N3wJY=
|
||||
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
|
@ -26,18 +30,29 @@ github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKt
|
|||
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||
github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0=
|
||||
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
|
||||
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/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
|
||||
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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=
|
||||
|
|
82
main.go
82
main.go
|
@ -1,11 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/caarlos0/log"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
@ -13,80 +8,27 @@ import (
|
|||
var Version = "develop"
|
||||
|
||||
func main() {
|
||||
languages := []string{"go", "rust"}
|
||||
cfg, err := loadConfig()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("could not load config")
|
||||
}
|
||||
|
||||
for _, lang := range languages {
|
||||
l, err := trendingLang(lang, []string{"daily", "weekly", "monthly"})
|
||||
for _, lang := range cfg.Languages {
|
||||
l, err := trendingLang(lang.Name, lang.Timeframes)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("could not get trending repositories")
|
||||
}
|
||||
log.Styles[log.InfoLevel] = lipgloss.NewStyle().Foreground(lipgloss.Color(l.color)).Bold(true)
|
||||
log.Info(lang)
|
||||
log.Info(lang.Name)
|
||||
log.IncreasePadding()
|
||||
for _, repo := range l.repositories {
|
||||
log.WithField("link", repo.link()).Info(repo.name)
|
||||
if repo.description != "" {
|
||||
log.IncreasePadding()
|
||||
log.Info(repo.description)
|
||||
log.DecreasePadding()
|
||||
}
|
||||
}
|
||||
log.ResetPadding()
|
||||
}
|
||||
}
|
||||
|
||||
func trendingLang(lang string, timeframes []string) (language, error) {
|
||||
l := language{
|
||||
repositories: make([]repository, 0),
|
||||
}
|
||||
repoMap := make(map[repository]struct{})
|
||||
for _, timeframe := range timeframes {
|
||||
la, err := trendingRepos(lang, timeframe)
|
||||
if err != nil {
|
||||
return la, err
|
||||
}
|
||||
l.color = la.color
|
||||
for _, r := range la.repositories {
|
||||
repoMap[r] = struct{}{}
|
||||
}
|
||||
}
|
||||
for repo := range repoMap {
|
||||
l.repositories = append(l.repositories, repo)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func trendingRepos(lang, timeframe string) (language, error) {
|
||||
u := fmt.Sprintf("https://github.com/trending/%s?since=%s", lang, timeframe)
|
||||
res, err := http.Get(u)
|
||||
if err != nil {
|
||||
return language{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
doc, err := goquery.NewDocumentFromReader(res.Body)
|
||||
if err != nil {
|
||||
return language{}, err
|
||||
}
|
||||
|
||||
var l language
|
||||
doc.Find(".Box-row").Each(func(_ int, s *goquery.Selection) {
|
||||
if l.color == "" {
|
||||
rlcStyle, _ := s.Find(".repo-language-color").Attr("style")
|
||||
l.color = strings.Fields(rlcStyle)[1]
|
||||
}
|
||||
|
||||
e := s.Find("h1 a")
|
||||
repo := strings.Join(strings.Fields(e.Text()), "")
|
||||
l.repositories = append(l.repositories, repository{name: repo})
|
||||
})
|
||||
return l, nil
|
||||
}
|
||||
|
||||
type language struct {
|
||||
color string
|
||||
repositories []repository
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (r repository) link() string {
|
||||
return fmt.Sprintf("https://github.com/%s", r.name)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
)
|
||||
|
||||
func trendingLang(lang string, timeframes []string) (language, error) {
|
||||
l := language{
|
||||
repositories: make([]repository, 0),
|
||||
}
|
||||
repoMap := make(map[repository]struct{})
|
||||
for _, timeframe := range timeframes {
|
||||
la, err := trendingRepos(lang, timeframe)
|
||||
if err != nil {
|
||||
return la, err
|
||||
}
|
||||
l.color = la.color
|
||||
for _, r := range la.repositories {
|
||||
repoMap[r] = struct{}{}
|
||||
}
|
||||
}
|
||||
for repo := range repoMap {
|
||||
l.repositories = append(l.repositories, repo)
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func trendingRepos(lang, timeframe string) (language, error) {
|
||||
u := fmt.Sprintf("https://github.com/trending/%s?since=%s", lang, timeframe)
|
||||
res, err := http.Get(u)
|
||||
if err != nil {
|
||||
return language{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
doc, err := goquery.NewDocumentFromReader(res.Body)
|
||||
if err != nil {
|
||||
return language{}, err
|
||||
}
|
||||
|
||||
var l language
|
||||
doc.Find(".Box-row").Each(func(_ int, s *goquery.Selection) {
|
||||
if l.color == "" {
|
||||
rlcStyle, _ := s.Find(".repo-language-color").Attr("style")
|
||||
l.color = strings.Fields(rlcStyle)[1]
|
||||
}
|
||||
|
||||
e := s.Find("h1 a")
|
||||
repo := strings.Join(strings.Fields(e.Text()), "")
|
||||
|
||||
d := strings.TrimSpace(s.Find("p").Text())
|
||||
|
||||
l.repositories = append(l.repositories, repository{name: repo, description: d})
|
||||
})
|
||||
return l, nil
|
||||
}
|
||||
|
||||
type language struct {
|
||||
color string
|
||||
repositories []repository
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
name string
|
||||
description string
|
||||
}
|
||||
|
||||
func (r repository) link() string {
|
||||
return fmt.Sprintf("https://github.com/%s", r.name)
|
||||
}
|
Loading…
Reference in New Issue