feat(dashboard): add opengraph/oembed, Docker build
This commit is contained in:
3
dashboard/.gitignore
vendored
3
dashboard/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
dist/
|
||||
node_modules/
|
||||
node_modules/
|
||||
dashboard
|
5
dashboard/go.mod
Normal file
5
dashboard/go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module dashboard
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/go-chi/chi v1.5.4 // indirect
|
2
dashboard/go.sum
Normal file
2
dashboard/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
|
||||
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
|
@@ -5,6 +5,7 @@
|
||||
<link rel="icon" href="./myriad.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>PluralKit | home</title>
|
||||
<!-- extra data -->
|
||||
<link rel="stylesheet" href="/styles/generic.scss" />
|
||||
<link rel="stylesheet" href="/styles/dark.scss" />
|
||||
<link rel="stylesheet" href="/styles/light.scss" />
|
||||
|
139
dashboard/main.go
Normal file
139
dashboard/main.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
//go:embed dist/*
|
||||
var fs embed.FS
|
||||
|
||||
type entity struct {
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
IconURL *string `json:"icon_url"`
|
||||
Description *string `json:"description"`
|
||||
Color *string `json:"color"`
|
||||
}
|
||||
|
||||
var baseURL = "https://api.pluralkit.me/v2"
|
||||
|
||||
var version = "dev"
|
||||
|
||||
func main() {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header().Set("X-PluralKit-Version", version)
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
})
|
||||
|
||||
r.NotFound(notFoundHandler)
|
||||
|
||||
r.Get("/profile/{type}/{id}", func(rw http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if a := recover(); a != nil {
|
||||
notFoundHandler(rw, r)
|
||||
return
|
||||
}
|
||||
}()
|
||||
createEmbed(rw, r)
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", r)
|
||||
}
|
||||
|
||||
func notFoundHandler(rw http.ResponseWriter, r *http.Request) {
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
// lol
|
||||
if strings.HasSuffix(r.URL.Path, ".js") {
|
||||
data, err = fs.ReadFile("dist" + r.URL.Path)
|
||||
rw.Header().Add("content-type", "application/javascript")
|
||||
} else if strings.HasSuffix(r.URL.Path, ".css") {
|
||||
data, err = fs.ReadFile("dist" + r.URL.Path)
|
||||
rw.Header().Add("content-type", "text/css")
|
||||
} else if strings.HasSuffix(r.URL.Path, ".map") {
|
||||
data, err = fs.ReadFile("dist" + r.URL.Path)
|
||||
} else {
|
||||
data, err = fs.ReadFile("dist/index.html")
|
||||
rw.Header().Add("content-type", "text/html")
|
||||
data = []byte(strings.Replace(string(data), `<!-- extra data -->`, "", 1))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rw.Write(data)
|
||||
}
|
||||
|
||||
// explanation for createEmbed:
|
||||
// we don't care about errors, we just want to return a HTML page as soon as possible
|
||||
// `panic(nil)` is caught by upstream, which then returns the raw HTML page
|
||||
|
||||
func createEmbed(rw http.ResponseWriter, r *http.Request) {
|
||||
entityType := chi.URLParam(r, "type")
|
||||
id := chi.URLParam(r, "id")
|
||||
|
||||
var path string
|
||||
|
||||
switch entityType {
|
||||
case "s":
|
||||
path = "/systems/" + id
|
||||
case "m":
|
||||
path = "/members/" + id
|
||||
case "g":
|
||||
path = "/groups/" + id
|
||||
default:
|
||||
panic(nil)
|
||||
}
|
||||
|
||||
res, err := http.Get(baseURL + path)
|
||||
if err != nil {
|
||||
panic(nil)
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
panic(nil)
|
||||
}
|
||||
|
||||
var data entity
|
||||
body, _ := io.ReadAll(res.Body)
|
||||
err = json.Unmarshal(body, &data)
|
||||
if err != nil {
|
||||
panic(nil)
|
||||
}
|
||||
|
||||
text := fmt.Sprintf(`<link type="application/json+oembed" href="%s/%s/oembed.json" />%s`, baseURL, path, "\n")
|
||||
|
||||
if data.AvatarURL != nil {
|
||||
text += fmt.Sprintf(`<meta content='%s' property='og:image'>%s`, *data.AvatarURL, "\n")
|
||||
} else if data.IconURL != nil {
|
||||
text += fmt.Sprintf(`<meta content='%s' property='og:image'>%s`, *data.IconURL, "\n")
|
||||
}
|
||||
|
||||
if data.Description != nil {
|
||||
text += fmt.Sprintf(`<meta content="%s" property="og:description">%s`, *data.Description, "\n")
|
||||
}
|
||||
|
||||
if data.Color != nil {
|
||||
text += fmt.Sprintf(`<meta name="theme-color" content="#%s">%s`, *data.Color, "\n")
|
||||
}
|
||||
|
||||
html, err := fs.ReadFile("dist/index.html")
|
||||
if err != nil {
|
||||
panic(nil)
|
||||
}
|
||||
html = []byte(strings.Replace(string(html), `<!-- extra data -->`, text, 1))
|
||||
|
||||
rw.Header().Add("content-type", "text/html")
|
||||
rw.Write(html)
|
||||
}
|
Reference in New Issue
Block a user