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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ make build

[Status Page](https://github.com/rramiachraf/dumb-instances)

#### API Endpoints:
- /api/v1/albums/{artist}/{albumName}
- /api/v1/artists/{artist}
- /api/v1/annotations/{annotation-id}
- /api/v1/search (eg. ../search?q=search+term)


#### Notes:
- Instances list in JSON format can be found in [instances.json](instances.json) file.
- For people who might be capable and interested in hosting a public instance feel free to do so, and don't forget to open a pull request, so your instance can be included here.
Expand All @@ -52,3 +59,6 @@ Contributions are welcome.
## License
[MIT](https://github.com/rramiachraf/dumb/blob/main/LICENCE)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the api should be mentioned in the readme.



8 changes: 6 additions & 2 deletions handlers/album.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func album(l *utils.Logger) http.HandlerFunc {
func (d ResponseType) albums(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
artist := mux.Vars(r)["artist"]
albumName := mux.Vars(r)["albumName"]
Expand Down Expand Up @@ -61,7 +61,11 @@ func album(l *utils.Logger) http.HandlerFunc {
l.Error(err.Error())
}

utils.RenderTemplate(w, views.AlbumPage(a), l)
if d.asApi {
utils.EncodeJSON(w, a, l)
} else {
utils.RenderTemplate(w, views.AlbumPage(a), l)
}

if err = setCache(id, a); err != nil {
l.Error(err.Error())
Expand Down
2 changes: 1 addition & 1 deletion handlers/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func annotations(l *utils.Logger) http.HandlerFunc {
func (rt ResponseType)annotations(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["annotation-id"]
if a, err := getCache[data.Annotation]("annotation:" + id); err == nil {
Expand Down
8 changes: 6 additions & 2 deletions handlers/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func article(l *utils.Logger) http.HandlerFunc {
func (rt ResponseType)article(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
articleSlug := mux.Vars(r)["article"]

Expand Down Expand Up @@ -58,7 +58,11 @@ func article(l *utils.Logger) http.HandlerFunc {
l.Error(err.Error())
}

utils.RenderTemplate(w, views.ArticlePage(a), l)
if rt.asApi {
utils.EncodeJSON(w, a, l)
} else {
utils.RenderTemplate(w, views.ArticlePage(a), l)
}

if err = setCache(articleSlug, a); err != nil {
l.Error(err.Error())
Expand Down
8 changes: 6 additions & 2 deletions handlers/artist.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func artist(l *utils.Logger) http.HandlerFunc {
func (rt ResponseType) artist(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
artistName := mux.Vars(r)["artist"]

Expand Down Expand Up @@ -60,7 +60,11 @@ func artist(l *utils.Logger) http.HandlerFunc {
l.Error(err.Error())
}

utils.RenderTemplate(w, views.ArtistPage(a), l)
if rt.asApi {
utils.EncodeJSON(w, a, l)
} else {
utils.RenderTemplate(w, views.ArtistPage(a), l)
}

if err = setCache(id, a); err != nil {
l.Error(err.Error())
Expand Down
30 changes: 21 additions & 9 deletions handlers/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,43 @@ type route struct {
Template func() templ.Component
}

type ResponseType struct {
asApi bool
}

func New(logger *utils.Logger, staticFiles static) *mux.Router {
r := mux.NewRouter()

r.Use(utils.MustHeaders)
r.Use(gorillaHandlers.CompressHandler)

rH := ResponseType{asApi: false}
rJ := ResponseType{asApi: true}

routes := []route{
{Path: "/", Template: views.HomePage},
{Path: "/robots.txt", Handler: robotsHandler},
{Path: "/albums/{artist}/{albumName}", Handler: album},
{Path: "/artists/{artist}", Handler: artist},
{Path: "/a/{article}", Handler: article},
{Path: "/albums/{artist}/{albumName}", Handler: rH.albums},
{Path: "/artists/{artist}", Handler: rH.artist},
{Path: "/a/{article}", Handler: rH.article},
{Path: "/images/{filename}.{ext}", Handler: imageProxy},
{Path: "/search", Handler: search},
{Path: "/{annotation-id}/{artist-song}/{verse}/annotations", Handler: annotations},
{Path: "/{annotation-id}/{artist-song}/annotations", Handler: annotations},
{Path: "/search", Handler: rH.search},
{Path: "/{annotation-id}/{artist-song}/{verse}/annotations", Handler: rH.annotations},
{Path: "/{annotation-id}/{artist-song}/annotations", Handler: rH.annotations},
{Path: "/instances.json", Handler: instances},

{Path: "api/v1/albums/{artist}/{albumName}", Handler: rJ.albums},
{Path: "api/v1/artists/{artist}", Handler: rJ.artist},
{Path: "api/v1/annotations/{annotation-id}", Handler: rJ.annotations},
{Path: "api/v1/search", Handler: rJ.search},
}

registerRoutes(r, routes, logger)

r.PathPrefix("/static/").HandlerFunc(staticAssets(logger, staticFiles))
r.PathPrefix("/{annotation-id}/{artist-song}-lyrics").HandlerFunc(lyrics(logger)).Methods("GET")
r.PathPrefix("/{annotation-id}/{artist-song}").HandlerFunc(lyrics(logger)).Methods("GET")
r.PathPrefix("/{annotation-id}").HandlerFunc(lyrics(logger)).Methods("GET")
r.PathPrefix("/{annotation-id}/{artist-song}-lyrics").HandlerFunc(rH.lyrics(logger)).Methods("GET")
r.PathPrefix("/{annotation-id}/{artist-song}").HandlerFunc(rH.lyrics(logger)).Methods("GET")
r.PathPrefix("/{annotation-id}").HandlerFunc(rH.lyrics(logger)).Methods("GET")

r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
Expand Down
8 changes: 6 additions & 2 deletions handlers/lyrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func lyrics(l *utils.Logger) http.HandlerFunc {
func (rt ResponseType) lyrics(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// prefer artist-song over annotation-id for cache key when available
id := mux.Vars(r)["artist-song"]
Expand Down Expand Up @@ -63,7 +63,11 @@ func lyrics(l *utils.Logger) http.HandlerFunc {
l.Error(err.Error())
}

utils.RenderTemplate(w, views.LyricsPage(s), l)
if rt.asApi {
utils.EncodeJSON(w, s, l)
} else {
utils.RenderTemplate(w, views.LyricsPage(s), l)
}

if err = setCache(id, s); err != nil {
l.Error(err.Error())
Expand Down
9 changes: 7 additions & 2 deletions handlers/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/rramiachraf/dumb/views"
)

func search(l *utils.Logger) http.HandlerFunc {
func (rt ResponseType) search(l *utils.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query().Get("q")
url := fmt.Sprintf(`https://genius.com/api/search/multi?q=%s`, url.QueryEscape(query))
Expand Down Expand Up @@ -45,7 +45,12 @@ func search(l *utils.Logger) http.HandlerFunc {

results := data.SearchResults{Query: query, Sections: sRes.Response.Sections}

utils.RenderTemplate(w, views.SearchPage(results), l)
if rt.asApi {
utils.EncodeJSON(w, results, l)
} else {
utils.RenderTemplate(w, views.SearchPage(results), l)
}

}

}
19 changes: 19 additions & 0 deletions utils/json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package utils

import (
"encoding/json"
"net/http"
)

func EncodeJSON(w http.ResponseWriter, data any, l *Logger) {
w.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(w)
if err := enc.Encode(data); err != nil {
l.Errorf("unable to render json %s", err)
w.WriteHeader(http.StatusInternalServerError)
_, err := w.Write([]byte{})
if err != nil {
l.Error(err.Error())
}
}
}