Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ Open a pull request against the README.md document that adds the repository to t
- Descriptions should be clear, concise, and non-promotional.
- Descriptions should follow the link on the same line and end with a punctuation mark.
- Remember to put a period `.` at the end of the project description.
- **Optional tags** can be added between the link and description to categorize the project:
- **Project type**: `[lib]` for libraries, `[app]` for applications
- **Maintenance status**: `[active]` (commits within 12 months), `[stalled]` (12-24 months), `[unmaintained]` (>24 months)

If you are creating a new category, move the projects that apply to the new category, ensuring
that the resulting list has at least 3 projects in every category, and that the categories are alphabetized.
Expand All @@ -124,6 +127,13 @@ Good:
- [project-name](https://github.com/org/project) - Short, clear description.
```

Good with tags:

```md
- [gin](https://github.com/gin-gonic/gin) `[lib]` `[active]` - HTTP web framework written in Go.
- [docker](https://github.com/docker/docker) `[app]` `[active]` - Platform for distributed applications.
```

Bad (not alphabetical):

```md
Expand Down
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ Please take a quick gander at the [contribution guidelines](https://github.com/a

> _If you see a package or project here that is no longer maintained or is not a good fit, please submit a pull request to improve this file. Thank you!_

**Tags:**

This list supports optional tags to help categorize projects:

- **Project Type**: `[lib]` for libraries, `[app]` for applications
- **Maintenance Status**: `[active]` (commits within 12 months), `[stalled]` (12-24 months), `[unmaintained]` (>24 months)

Example: - [gin](https://github.com/gin-gonic/gin) `[lib]` `[active]` - HTTP web framework written in Go.

## Contents

<details>
Expand Down Expand Up @@ -221,12 +230,12 @@ _Libraries for building actor-based programs._

_Libraries for building programs that leverage AI._

- [chromem-go](https://github.com/philippgille/chromem-go) - Embeddable vector database for Go with Chroma-like interface and zero third-party dependencies. In-memory with optional persistence.
- [fun](https://gitlab.com/tozd/go/fun) - The simplest but powerful way to use large language models (LLMs) in Go.
- [langchaingo](https://github.com/tmc/langchaingo) - LangChainGo is a framework for developing applications powered by language models.
- [LocalAI](https://github.com/mudler/LocalAI) - Open Source OpenAI alternative, self-host AI models.
- [Ollama](https://github.com/jmorganca/ollama) - Run large language models locally.
- [OllamaFarm](https://github.com/presbrey/ollamafarm) - Manage, load-balance, and failover packs of Ollamas.
- [chromem-go](https://github.com/philippgille/chromem-go) `[lib]` `[active]` - Embeddable vector database for Go with Chroma-like interface and zero third-party dependencies. In-memory with optional persistence.
- [fun](https://gitlab.com/tozd/go/fun) `[lib]` `[active]` - The simplest but powerful way to use large language models (LLMs) in Go.
- [langchaingo](https://github.com/tmc/langchaingo) `[lib]` `[active]` - LangChainGo is a framework for developing applications powered by language models.
- [LocalAI](https://github.com/mudler/LocalAI) `[app]` `[active]` - Open Source OpenAI alternative, self-host AI models.
- [Ollama](https://github.com/jmorganca/ollama) `[app]` `[active]` - Run large language models locally.
- [OllamaFarm](https://github.com/presbrey/ollamafarm) `[app]` `[active]` - Manage, load-balance, and failover packs of Ollamas.

**[⬆ back to top](#contents)**

Expand All @@ -236,27 +245,27 @@ _Libraries for building programs that leverage AI._

_Libraries for manipulating audio._

- [beep](https://github.com/faiface/beep) - A simple library for playback and audio manipulation.
- [flac](https://github.com/mewkiz/flac) - Native Go FLAC encoder/decoder with support for FLAC streams.
- [gaad](https://github.com/Comcast/gaad) - Native Go AAC bitstream parser.
- [go-mpris](https://github.com/leberKleber/go-mpris) - Client for mpris dbus interfaces.
- [GoAudio](https://github.com/DylanMeeus/GoAudio) - Native Go Audio Processing Library.
- [gosamplerate](https://github.com/dh1tw/gosamplerate) - libsamplerate bindings for go.
- [id3v2](https://github.com/bogem/id3v2) - ID3 decoding and encoding library for Go.
- [malgo](https://github.com/gen2brain/malgo) - Mini audio library.
- [minimp3](https://github.com/tosone/minimp3) - Lightweight MP3 decoder library.
- [Oto](https://github.com/hajimehoshi/oto) - A low-level library to play sound on multiple platforms.
- [PortAudio](https://github.com/gordonklaus/portaudio) - Go bindings for the PortAudio audio I/O library.
- [beep](https://github.com/faiface/beep) `[lib]` `[active]` - A simple library for playback and audio manipulation.
- [flac](https://github.com/mewkiz/flac) `[lib]` `[active]` - Native Go FLAC encoder/decoder with support for FLAC streams.
- [gaad](https://github.com/Comcast/gaad) `[lib]` `[active]` - Native Go AAC bitstream parser.
- [go-mpris](https://github.com/leberKleber/go-mpris) `[lib]` `[active]` - Client for mpris dbus interfaces.
- [GoAudio](https://github.com/DylanMeeus/GoAudio) `[lib]` `[active]` - Native Go Audio Processing Library.
- [gosamplerate](https://github.com/dh1tw/gosamplerate) `[lib]` `[active]` - libsamplerate bindings for go.
- [id3v2](https://github.com/bogem/id3v2) `[lib]` `[active]` - ID3 decoding and encoding library for Go.
- [malgo](https://github.com/gen2brain/malgo) `[lib]` `[active]` - Mini audio library.
- [minimp3](https://github.com/tosone/minimp3) `[lib]` `[active]` - Lightweight MP3 decoder library.
- [Oto](https://github.com/hajimehoshi/oto) `[lib]` `[active]` - A low-level library to play sound on multiple platforms.
- [PortAudio](https://github.com/gordonklaus/portaudio) `[lib]` `[active]` - Go bindings for the PortAudio audio I/O library.

**[⬆ back to top](#contents)**

## Authentication and Authorization

_Libraries for implementing authentication and authorization._

- [authboss](https://github.com/volatiletech/authboss) - Modular authentication system for the web. It tries to remove as much boilerplate and "hard things" as possible so that each time you start a new web project in Go, you can plug it in, configure it, and start building your app without having to build an authentication system each time.
- [branca](https://github.com/essentialkaos/branca) - branca token [specification implementation](https://github.com/tuupola/branca-spec) for Golang 1.15+.
- [casbin](https://github.com/hsluoyz/casbin) - Authorization library that supports access control models like ACL, RBAC, and ABAC.
- [authboss](https://github.com/volatiletech/authboss) `[lib]` `[active]` - Modular authentication system for the web. It tries to remove as much boilerplate and "hard things" as possible so that each time you start a new web project in Go, you can plug it in, configure it, and start building your app without having to build an authentication system each time.
- [branca](https://github.com/essentialkaos/branca) `[lib]` `[active]` - branca token [specification implementation](https://github.com/tuupola/branca-spec) for Golang 1.15+.
- [casbin](https://github.com/hsluoyz/casbin) `[lib]` `[active]` - Authorization library that supports access control models like ACL, RBAC, and ABAC.
- [cookiestxt](https://github.com/mengzhuo/cookiestxt) - provides a parser of cookies.txt file format.
- [go-iam](https://github.com/melvinodsa/go-iam) - Developer-first Identity and Access Management system with a simple UI.
- [go-jose](https://github.com/go-jose/go-jose) - Fairly complete implementation of the JOSE working group's JSON Web Token, JSON Web Signatures, and JSON Web Encryption specs.
Expand Down
88 changes: 67 additions & 21 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ package main
import (
"bytes"
"embed"
"errors"
"fmt"
template2 "html/template"
"net/url"
"os"
"path/filepath"
"strings"
"text/template"

"github.com/avelino/awesome-go/pkg/markdown"
Expand All @@ -24,6 +24,7 @@ type Link struct {
Title string
URL string
Description string
Tags []string
}

// Category describe link category
Expand All @@ -47,7 +48,9 @@ var staticFiles = []string{
//go:embed tmpl/*.tmpl.html tmpl/*.tmpl.xml
var tplFs embed.FS

var tpl = template.Must(template.ParseFS(tplFs, "tmpl/*.tmpl.html", "tmpl/*.tmpl.xml"))
var tpl = template.Must(template.New("").Funcs(template.FuncMap{
"upper": strings.ToUpper,
}).ParseFS(tplFs, "tmpl/*.tmpl.html", "tmpl/*.tmpl.xml"))

// Output files
const outDir = "out/" // NOTE: trailing slash is required
Expand Down Expand Up @@ -108,6 +111,18 @@ func buildStaticSite() error {
return nil
}

// isValidTag checks if a tag is in the allowed list
func isValidTag(tag string) bool {
validTags := map[string]bool{
"lib": true,
"app": true,
"active": true,
"stalled": true,
"unmaintained": true,
}
return validTags[tag]
}

// dropCreateDir drop and create output directory
func dropCreateDir(dir string) error {
if err := os.RemoveAll(dir); err != nil {
Expand Down Expand Up @@ -198,14 +213,21 @@ func extractCategories(doc *goquery.Document) (map[string]Category, error) {
categories := make(map[string]Category)
var rootErr error

doc.
Find("body #contents").
NextFiltered("ul").
Find("ul").
EachWithBreak(func(_ int, selUl *goquery.Selection) bool {
if rootErr != nil {
return false
}
// Try multiple selectors to find the navigation structure
selector := doc.Find("body #contents").NextFiltered("details").Find("ul ul")
if selector.Length() == 0 {
selector = doc.Find("body #contents").NextFiltered("ul").Find("ul")
}

// Post-fallback check: ensure we found a valid navigation structure
if selector.Length() == 0 {
return nil, fmt.Errorf("no navigation structure found with known selectors")
}

selector.EachWithBreak(func(_ int, selUl *goquery.Selection) bool {
if rootErr != nil {
return false
}

selUl.
Find("li a").
Expand Down Expand Up @@ -238,7 +260,6 @@ func extractCategories(doc *goquery.Document) (map[string]Category, error) {

func extractCategory(doc *goquery.Document, selector string) (*Category, error) {
var category Category
var err error

doc.Find(selector).EachWithBreak(func(_ int, selCatHeader *goquery.Selection) bool {
selDescr := selCatHeader.NextFiltered("p")
Expand All @@ -251,20 +272,49 @@ func extractCategory(doc *goquery.Document, selector string) (*Category, error)
ul.Find("li").Each(func(_ int, selLi *goquery.Selection) {
selLink := selLi.Find("a")
url, _ := selLink.Attr("href")
title := selLink.Text()

// Extract tags from code elements (which are converted from backticks)
var tags []string
selLi.Find("code").Each(func(_ int, codeEl *goquery.Selection) {
codeText := codeEl.Text()
// Check if it matches tag pattern [tagname]
if len(codeText) > 2 && codeText[0] == '[' && codeText[len(codeText)-1] == ']' {
tag := strings.ToLower(strings.TrimSpace(codeText[1 : len(codeText)-1]))
if isValidTag(tag) {
tags = append(tags, tag)
}
}
})

// Remove only code elements that are valid tags, preserve inline code like `net/http`, `[1]`, `[gin]`
clonedLi := selLi.Clone()
clonedLi.Find("code").Each(func(i int, codeEl *goquery.Selection) {
codeText := strings.TrimSpace(codeEl.Text())
if isValidTag(codeText) {
codeEl.Remove()
}
})
fullText := clonedLi.Text()

// Remove the title from the beginning and trim
description := strings.TrimSpace(strings.TrimPrefix(fullText, title))
// Remove leading dash if present
description = strings.TrimSpace(strings.TrimPrefix(description, "-"))

link := Link{
Title: selLink.Text(),
// FIXME(kazhuravlev): Title contains only title but
// description contains Title + description
Description: selLi.Text(),
Title: title,
Description: description,
URL: url,
Tags: tags,
}
links = append(links, link)
})

// FIXME: In this case we would have an empty category in main index.html with link to 404 page.
if len(links) == 0 {
err = errors.New("category does not contain links")
return false
// Skip categories without links instead of erroring
return true
}

category = Category{
Expand All @@ -277,10 +327,6 @@ func extractCategory(doc *goquery.Document, selector string) (*Category, error)
return true
})

if err != nil {
return nil, fmt.Errorf("build a category: %w", err)
}

return &category, nil
}

Expand Down
36 changes: 36 additions & 0 deletions tmpl/assets/awesome-go.css
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,39 @@ h1 > a img {
td {
padding: 6px;
}

/* Tag styles */
.tag {
font-size: 0.7em;
padding: 2px 6px;
border-radius: 3px;
margin: 0 2px;
font-weight: 500;
display: inline-block;
vertical-align: middle;
}

.tag-lib {
background: #e3f2fd;
color: #0d47a1;
}

.tag-app {
background: #f3e5f5;
color: #7b1fa2;
}

.tag-active {
background: #e8f5e8;
color: #2e7d32;
}

.tag-stalled {
background: #fff3e0;
color: #bf360c;
}

.tag-unmaintained {
background: #ffebee;
color: #c62828;
}
2 changes: 1 addition & 1 deletion tmpl/category-index.tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ <h1><a href="https://awesome-go.com/"><img align=
<a href=
"{{.URL}}?utm_campaign=awesomego&amp;utm_medium=referral&amp;utm_source=awesomego"
alt="Go to {{.Title}} link" title=
"Go to {{.Title}} link">{{.Description}}</a>
"Go to {{.Title}} link">{{.Title}}</a>{{range .Tags}} <span class="tag tag-{{.}}">[{{. | upper}}]</span>{{end}}{{if .Description}} - {{.Description}}{{end}}
</li>{{end}}
</ul><a href="https://bit.ly/awesome-go-netlify"><img src=
"https://www.netlify.com/img/global/badges/netlify-dark.svg"
Expand Down
Loading