port to fiber v3, optimize static assets serving

This commit is contained in:
Laptop
2024-12-31 16:22:23 +02:00
parent f122c45fec
commit 1d5ec4353e
13 changed files with 176 additions and 92 deletions

View File

@@ -8,7 +8,10 @@ LICENSE
README.md README.md
docs docs
*.fiber.gz .compression
.br
.gzip
.zstd
*_templ.go *_templ.go
regexp2_codegen.go regexp2_codegen.go
main main

5
.gitignore vendored
View File

@@ -10,7 +10,10 @@ compose.yaml
fly.toml fly.toml
# created by soundcloak/dependencies # created by soundcloak/dependencies
*.fiber.gz .compression
*.br
*.gzip
*.zstd
# codegen # codegen
*_templ.go *_templ.go

View File

@@ -1,4 +1,4 @@
ARG GO_VERSION=1.22.10 ARG GO_VERSION=1.23.4
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS build FROM --platform=$BUILDPLATFORM golang:${GO_VERSION} AS build
ARG TARGETOS ARG TARGETOS
@@ -20,6 +20,7 @@ RUN soundcloakctl js download
RUN templ generate RUN templ generate
RUN go generate ./lib/* RUN go generate ./lib/*
RUN soundcloakctl config codegen RUN soundcloakctl config codegen
RUN soundcloakctl -nozstd -notable precompress
RUN CGO_ENABLED=0 GOARCH=${TARGETARCH} GOOS=${TARGETOS} go build -ldflags "-s -w -extldflags '-static'" -o ./app RUN CGO_ENABLED=0 GOARCH=${TARGETARCH} GOOS=${TARGETOS} go build -ldflags "-s -w -extldflags '-static'" -o ./app
RUN echo "soundcloak:x:5000:5000:Soundcloak user:/:/sbin/nologin" > /etc/minimal-passwd && \ RUN echo "soundcloak:x:5000:5000:Soundcloak user:/:/sbin/nologin" > /etc/minimal-passwd && \

View File

@@ -1,6 +1,6 @@
# Setup # Setup
## Prerequisites ## Prerequisites
1. [golang](https://go.dev) (I recommend version 1.22.10. Technically, you need 1.21.4 or higher) 1. [golang](https://go.dev) (I recommend version 1.23.4)
2. [git](https://git-scm.com) 2. [git](https://git-scm.com)
## The setup ## The setup
@@ -90,9 +90,9 @@ soundcloakctl js download # re-download JS modules
3. Clean precompressed static files 3. Clean precompressed static files
Those are created by the webserver in order to more efficiently serve static files. They have the `.fiber.gz` extension. You can easily remove them from all directories like this: Those are created by the webserver in order to more efficiently serve static files. They have the `.br` and `.gzip` extension. You can easily remove them from all directories using soundcloakctl:
```sh ```sh
find . -name \*.fiber.gz -type f -delete soundcloakctl clean
``` ```
4. Run codegen and build the binary: 4. Run codegen and build the binary:

7
go.mod
View File

@@ -1,6 +1,6 @@
module git.maid.zone/stuff/soundcloak module git.maid.zone/stuff/soundcloak
go 1.22.10 go 1.23.4
require ( require (
github.com/a-h/templ v0.2.793 github.com/a-h/templ v0.2.793
@@ -9,7 +9,7 @@ require (
github.com/gcottom/mp4meta v0.0.4 github.com/gcottom/mp4meta v0.0.4
github.com/gcottom/oggmeta v0.0.7 github.com/gcottom/oggmeta v0.0.7
github.com/goccy/go-json v0.10.4 github.com/goccy/go-json v0.10.4
github.com/gofiber/fiber/v2 v2.52.5 github.com/gofiber/fiber/v3 v3.0.0-beta.3
github.com/valyala/fasthttp v1.58.0 github.com/valyala/fasthttp v1.58.0
) )
@@ -17,12 +17,11 @@ require (
github.com/abema/go-mp4 v1.2.0 // indirect github.com/abema/go-mp4 v1.2.0 // indirect
github.com/aler9/writerseeker v1.1.0 // indirect github.com/aler9/writerseeker v1.1.0 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/gofiber/utils/v2 v2.0.0-beta.4 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sunfish-shogi/bufseekio v0.1.0 // indirect github.com/sunfish-shogi/bufseekio v0.1.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect

11
go.sum
View File

@@ -20,8 +20,10 @@ github.com/gcottom/oggmeta v0.0.7 h1:6mKm/9xhDeKKIOrB0K+daJoXOLbyRq84e5xV3dndDt8
github.com/gcottom/oggmeta v0.0.7/go.mod h1:ifdINhphaEW587BIgA+m5TJwCoVk88JuZMCHwXc/gpM= github.com/gcottom/oggmeta v0.0.7/go.mod h1:ifdINhphaEW587BIgA+m5TJwCoVk88JuZMCHwXc/gpM=
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg=
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY=
github.com/gofiber/utils/v2 v2.0.0-beta.4 h1:1gjbVFFwVwUb9arPcqiB6iEjHBwo7cHsyS41NeIW3co=
github.com/gofiber/utils/v2 v2.0.0-beta.4/go.mod h1:sdRsPU1FXX6YiDGGxd+q2aPJRMzpsxdzCXo9dz+xtOY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -38,15 +40,10 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw= github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw=
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0= github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

View File

@@ -538,7 +538,7 @@ func init() {
} }
} }
const Debug = false const Debug = true
const Commit = "unknown" const Commit = "unknown"
const Repo = "unknown" const Repo = "unknown"
const CommitURL = "unknown" const CommitURL = "unknown"

View File

@@ -8,7 +8,7 @@ import (
"git.maid.zone/stuff/soundcloak/lib/cfg" "git.maid.zone/stuff/soundcloak/lib/cfg"
"git.maid.zone/stuff/soundcloak/templates" "git.maid.zone/stuff/soundcloak/templates"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v3"
) )
func Defaults(dst *cfg.Preferences) { func Defaults(dst *cfg.Preferences) {
@@ -61,7 +61,7 @@ func Defaults(dst *cfg.Preferences) {
} }
} }
func Get(c *fiber.Ctx) (cfg.Preferences, error) { func Get(c fiber.Ctx) (cfg.Preferences, error) {
rawprefs := c.Cookies("prefs", "{}") rawprefs := c.Cookies("prefs", "{}")
var p cfg.Preferences var p cfg.Preferences
@@ -94,7 +94,7 @@ type Export struct {
} }
func Load(r fiber.Router) { func Load(r fiber.Router) {
r.Get("/_/preferences", func(c *fiber.Ctx) error { r.Get("/_/preferences", func(c fiber.Ctx) error {
p, err := Get(c) p, err := Get(c)
if err != nil { if err != nil {
return err return err
@@ -104,9 +104,9 @@ func Load(r fiber.Router) {
return templates.Base("preferences", templates.Preferences(p), nil).Render(context.Background(), c) return templates.Base("preferences", templates.Preferences(p), nil).Render(context.Background(), c)
}) })
r.Post("/_/preferences", func(c *fiber.Ctx) error { r.Post("/_/preferences", func(c fiber.Ctx) error {
var p PrefsForm var p PrefsForm
err := c.BodyParser(&p) err := c.Bind().Body(&p)
if err != nil { if err != nil {
return err return err
} }
@@ -193,10 +193,10 @@ func Load(r fiber.Router) {
SameSite: "strict", SameSite: "strict",
}) })
return c.Redirect("/_/preferences") return c.Redirect().To("/_/preferences")
}) })
r.Get("/_/preferences/reset", func(c *fiber.Ctx) error { r.Get("/_/preferences/reset", func(c fiber.Ctx) error {
// c.ClearCookie("prefs") // c.ClearCookie("prefs")
c.Cookie(&fiber.Cookie{ // I've had some issues with c.ClearCookie() method, so using this workaround for now c.Cookie(&fiber.Cookie{ // I've had some issues with c.ClearCookie() method, so using this workaround for now
Name: "prefs", Name: "prefs",
@@ -206,10 +206,10 @@ func Load(r fiber.Router) {
SameSite: "strict", SameSite: "strict",
}) })
return c.Redirect("/_/preferences") return c.Redirect().To("/_/preferences")
}) })
r.Get("/_/preferences/export", func(c *fiber.Ctx) error { r.Get("/_/preferences/export", func(c fiber.Ctx) error {
p, err := Get(c) p, err := Get(c)
if err != nil { if err != nil {
return err return err
@@ -218,7 +218,7 @@ func Load(r fiber.Router) {
return c.JSON(Export{Preferences: &p}) return c.JSON(Export{Preferences: &p})
}) })
r.Post("/_/preferences/import", func(c *fiber.Ctx) error { r.Post("/_/preferences/import", func(c fiber.Ctx) error {
f, err := c.FormFile("prefs") f, err := c.FormFile("prefs")
if err != nil { if err != nil {
return err return err
@@ -257,6 +257,6 @@ func Load(r fiber.Router) {
SameSite: "strict", SameSite: "strict",
}) })
return c.Redirect("/_/preferences") return c.Redirect().To("/_/preferences")
}) })
} }

View File

@@ -6,7 +6,7 @@ import (
"git.maid.zone/stuff/soundcloak/lib/cfg" "git.maid.zone/stuff/soundcloak/lib/cfg"
"git.maid.zone/stuff/soundcloak/lib/misc" "git.maid.zone/stuff/soundcloak/lib/misc"
"git.maid.zone/stuff/soundcloak/lib/sc" "git.maid.zone/stuff/soundcloak/lib/sc"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v3"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@@ -32,7 +32,7 @@ func Load(r fiber.Router) {
StreamResponseBody: true, StreamResponseBody: true,
} }
r.Get("/_/proxy/images", func(c *fiber.Ctx) error { r.Get("/_/proxy/images", func(c fiber.Ctx) error {
url := c.Query("url") url := c.Query("url")
if url == "" { if url == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest

View File

@@ -7,7 +7,7 @@ import (
"git.maid.zone/stuff/soundcloak/lib/cfg" "git.maid.zone/stuff/soundcloak/lib/cfg"
"git.maid.zone/stuff/soundcloak/lib/misc" "git.maid.zone/stuff/soundcloak/lib/misc"
"git.maid.zone/stuff/soundcloak/lib/sc" "git.maid.zone/stuff/soundcloak/lib/sc"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v3"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@@ -33,7 +33,7 @@ func Load(r fiber.Router) {
StreamResponseBody: true, StreamResponseBody: true,
} }
r.Get("/_/proxy/streams", func(c *fiber.Ctx) error { r.Get("/_/proxy/streams", func(c fiber.Ctx) error {
ur := c.Query("url") ur := c.Query("url")
if ur == "" { if ur == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest
@@ -72,7 +72,7 @@ func Load(r fiber.Router) {
return c.SendStream(pr) return c.SendStream(pr)
}) })
r.Get("/_/proxy/streams/aac", func(c *fiber.Ctx) error { r.Get("/_/proxy/streams/aac", func(c fiber.Ctx) error {
ur := c.Query("url") ur := c.Query("url")
if ur == "" { if ur == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest
@@ -110,7 +110,7 @@ func Load(r fiber.Router) {
return c.SendStream(pr) return c.SendStream(pr)
}) })
r.Get("/_/proxy/streams/playlist", func(c *fiber.Ctx) error { r.Get("/_/proxy/streams/playlist", func(c fiber.Ctx) error {
ur := c.Query("url") ur := c.Query("url")
if ur == "" { if ur == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest
@@ -161,7 +161,7 @@ func Load(r fiber.Router) {
return c.Send(bytes.Join(sp, []byte("\n"))) return c.Send(bytes.Join(sp, []byte("\n")))
}) })
r.Get("/_/proxy/streams/playlist/aac", func(c *fiber.Ctx) error { r.Get("/_/proxy/streams/playlist/aac", func(c fiber.Ctx) error {
ur := c.Query("url") ur := c.Query("url")
if ur == "" { if ur == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest

View File

@@ -13,7 +13,7 @@ import (
"github.com/bogem/id3v2/v2" "github.com/bogem/id3v2/v2"
"github.com/gcottom/mp4meta" "github.com/gcottom/mp4meta"
"github.com/gcottom/oggmeta" "github.com/gcottom/oggmeta"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v3"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@@ -220,7 +220,7 @@ func Load(r fiber.Router) {
StreamResponseBody: true, StreamResponseBody: true,
} }
r.Get("/_/restream/:author/:track", func(c *fiber.Ctx) error { r.Get("/_/restream/:author/:track", func(c fiber.Ctx) error {
p, err := preferences.Get(c) p, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err

188
main.go
View File

@@ -1,18 +1,19 @@
package main package main
import ( import (
"io/fs"
"log" "log"
"math/rand" "math/rand"
"net/http"
"net/url" "net/url"
"os"
"strings" "strings"
"github.com/gofiber/fiber/v2" "git.maid.zone/stuff/soundcloak/lib/misc"
"github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v2/middleware/filesystem"
"github.com/goccy/go-json" "github.com/goccy/go-json"
"github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v3/middleware/compress"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"git.maid.zone/stuff/soundcloak/lib/cfg" "git.maid.zone/stuff/soundcloak/lib/cfg"
@@ -21,13 +22,81 @@ import (
proxystreams "git.maid.zone/stuff/soundcloak/lib/proxy_streams" proxystreams "git.maid.zone/stuff/soundcloak/lib/proxy_streams"
"git.maid.zone/stuff/soundcloak/lib/restream" "git.maid.zone/stuff/soundcloak/lib/restream"
"git.maid.zone/stuff/soundcloak/lib/sc" "git.maid.zone/stuff/soundcloak/lib/sc"
"git.maid.zone/stuff/soundcloak/static" static_files "git.maid.zone/stuff/soundcloak/static"
"git.maid.zone/stuff/soundcloak/templates" "git.maid.zone/stuff/soundcloak/templates"
) )
type osfs struct{}
func (osfs) Open(name string) (fs.File, error) {
misc.Log("osfs:", name)
if strings.HasPrefix(name, "js/") {
return os.Open("static/external/" + name[3:])
}
f, err := os.Open("static/instance/" + name)
if err == nil {
return f, nil
}
f, err = os.Open("static/assets/" + name)
return f, err
}
type staticfs struct {
}
func (staticfs) Open(name string) (fs.File, error) {
misc.Log("staticfs:", name)
if strings.HasPrefix(name, "js/") {
return static_files.External.Open("external/" + name[3:])
}
f, err := static_files.Instance.Open("instance/" + name)
if err == nil {
return f, nil
}
f, err = static_files.Assets.Open("assets/" + name)
return f, err
}
// stubby implementation of static middleware
// why? mainly because of the pathrewrite
// i hate seeing it trying to get root directory
func ServeFromFS(r fiber.Router, path string, filesystem fs.FS, cachecontrol string, compress bool) {
l := len(path)
fs := fasthttp.FS{
FS: filesystem,
PathRewrite: func(ctx *fasthttp.RequestCtx) []byte {
return ctx.Path()[l:]
},
Compress: compress,
CompressBrotli: compress,
CompressedFileSuffixes: map[string]string{
"gzip": ".gzip",
"br": ".br",
"zstd": ".zstd",
},
}
handler := fs.NewRequestHandler()
r.Use(path, func(c fiber.Ctx) error {
handler(c.Context())
if c.Context().Response.StatusCode() == 200 {
c.Set("Cache-Control", cachecontrol)
}
return nil
})
}
func main() { func main() {
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
Prefork: cfg.Prefork, //Prefork: cfg.Prefork, // moved to ListenConfig in v3
JSONEncoder: json.Marshal, JSONEncoder: json.Marshal,
JSONDecoder: json.Unmarshal, JSONDecoder: json.Unmarshal,
@@ -38,29 +107,35 @@ func main() {
if !cfg.Debug { // you wanna catch any possible panics as soon as possible if !cfg.Debug { // you wanna catch any possible panics as soon as possible
app.Use(recover.New()) app.Use(recover.New())
} }
app.Use(compress.New(compress.Config{Level: compress.LevelBestSpeed}))
app.Use(compress.New(compress.Config{
Next: func(c fiber.Ctx) bool {
return strings.HasPrefix(c.Path(), "/_/static")
},
Level: compress.LevelBestSpeed,
}))
// Just for easy inspection of cache in development. Since debug is constant, the compiler will just remove the code below if it's set to false, so this has no runtime overhead. // Just for easy inspection of cache in development. Since debug is constant, the compiler will just remove the code below if it's set to false, so this has no runtime overhead.
if cfg.Debug { if cfg.Debug {
app.Get("/_/cachedump/tracks", func(c *fiber.Ctx) error { app.Get("/_/cachedump/tracks", func(c fiber.Ctx) error {
return c.JSON(sc.TracksCache) return c.JSON(sc.TracksCache)
}) })
app.Get("/_/cachedump/playlists", func(c *fiber.Ctx) error { app.Get("/_/cachedump/playlists", func(c fiber.Ctx) error {
return c.JSON(sc.PlaylistsCache) return c.JSON(sc.PlaylistsCache)
}) })
app.Get("/_/cachedump/users", func(c *fiber.Ctx) error { app.Get("/_/cachedump/users", func(c fiber.Ctx) error {
return c.JSON(sc.UsersCache) return c.JSON(sc.UsersCache)
}) })
app.Get("/_/cachedump/clientId", func(c *fiber.Ctx) error { app.Get("/_/cachedump/clientId", func(c fiber.Ctx) error {
return c.JSON(sc.ClientIDCache) return c.JSON(sc.ClientIDCache)
}) })
} }
{ {
mainPageHandler := func(c *fiber.Ctx) error { mainPageHandler := func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -74,20 +149,25 @@ func main() {
app.Get("/index.html", mainPageHandler) app.Get("/index.html", mainPageHandler)
} }
const InstanceMaxAge = 7200 // 2hrs const AssetsCacheControl = "public, max-age=28800" // 8hrs
const AssetsMaxAge = 14400 // 4hrs
const ExternalMaxAge = 28800 // 8hrs
if cfg.EmbedFiles { if cfg.EmbedFiles {
app.Use("/_/static/", filesystem.New(filesystem.Config{Root: http.FS(static.Instance), PathPrefix: "instance", MaxAge: InstanceMaxAge})) misc.Log("using embedded files")
app.Use("/_/static/", filesystem.New(filesystem.Config{Root: http.FS(static.Assets), PathPrefix: "assets", MaxAge: AssetsMaxAge})) ServeFromFS(app, "/_/static", staticfs{}, AssetsCacheControl, true)
app.Use("/_/static/js/", filesystem.New(filesystem.Config{Root: http.FS(static.External), PathPrefix: "external", MaxAge: ExternalMaxAge}))
} else { } else {
app.Static("/_/static/", "static/instance", fiber.Static{Compress: true, MaxAge: InstanceMaxAge}) misc.Log("loading files dynamically")
app.Static("/_/static/", "static/assets", fiber.Static{Compress: true, MaxAge: AssetsMaxAge}) ServeFromFS(app, "/_/static", osfs{}, AssetsCacheControl, true)
app.Static("/_/static/js/", "static/external", fiber.Static{Compress: true, MaxAge: ExternalMaxAge})
} }
app.Get("/search", func(c *fiber.Ctx) error { // why? because when you load a page without link rel="icon" the browser will
// try to load favicon from default location,
// and this path loads the user "favicon.ico" by default
if cfg.Debug {
app.Get("favicon.ico", func(c fiber.Ctx) error {
return c.Redirect().To("/_/static/favicon.ico")
})
}
app.Get("/search", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -132,15 +212,15 @@ func main() {
// someone is trying to hit those endpoints on sc.maid.zone at like 4am lol // someone is trying to hit those endpoints on sc.maid.zone at like 4am lol
// those are authentication-only, planning to make something similar later on // those are authentication-only, planning to make something similar later on
app.Get("/stream", func(c *fiber.Ctx) error { app.Get("/stream", func(c fiber.Ctx) error {
return c.Redirect("/") return c.Redirect().To("/")
}) })
app.Get("/feed", func(c *fiber.Ctx) error { app.Get("/feed", func(c fiber.Ctx) error {
return c.Redirect("/") return c.Redirect().To("/")
}) })
app.Get("/on/:id", func(c *fiber.Ctx) error { app.Get("/on/:id", func(c fiber.Ctx) error {
id := c.Params("id") id := c.Params("id")
if id == "" { if id == "" {
return fiber.ErrNotFound return fiber.ErrNotFound
@@ -173,10 +253,10 @@ func main() {
return err return err
} }
return c.Redirect(u.Path) return c.Redirect().To(u.Path)
}) })
app.Get("/w/player", func(c *fiber.Ctx) error { app.Get("/w/player", func(c fiber.Ctx) error {
u := c.Query("url") u := c.Query("url")
if u == "" { if u == "" {
return fiber.ErrNotFound return fiber.ErrNotFound
@@ -222,7 +302,7 @@ func main() {
return templates.TrackEmbed(prefs, track, stream, displayErr).Render(c.Context(), c) return templates.TrackEmbed(prefs, track, stream, displayErr).Render(c.Context(), c)
}) })
app.Get("/tags/:tag", func(c *fiber.Ctx) error { app.Get("/tags/:tag", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -244,7 +324,7 @@ func main() {
return templates.Base("Recent tracks tagged "+tag, templates.RecentTracks(tag, p), nil).Render(c.Context(), c) return templates.Base("Recent tracks tagged "+tag, templates.RecentTracks(tag, p), nil).Render(c.Context(), c)
}) })
app.Get("/tags/:tag/popular-tracks", func(c *fiber.Ctx) error { app.Get("/tags/:tag/popular-tracks", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -266,7 +346,7 @@ func main() {
return templates.Base("Popular tracks tagged "+tag, templates.PopularTracks(tag, p), nil).Render(c.Context(), c) return templates.Base("Popular tracks tagged "+tag, templates.PopularTracks(tag, p), nil).Render(c.Context(), c)
}) })
app.Get("/tags/:tag/playlists", func(c *fiber.Ctx) error { app.Get("/tags/:tag/playlists", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -289,7 +369,7 @@ func main() {
return templates.Base("Playlists tagged "+tag, templates.TaggedPlaylists(tag, p), nil).Render(c.Context(), c) return templates.Base("Playlists tagged "+tag, templates.TaggedPlaylists(tag, p), nil).Render(c.Context(), c)
}) })
app.Get("/_/featured", func(c *fiber.Ctx) error { app.Get("/_/featured", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -305,7 +385,7 @@ func main() {
return templates.Base("Featured Tracks", templates.FeaturedTracks(tracks), nil).Render(c.Context(), c) return templates.Base("Featured Tracks", templates.FeaturedTracks(tracks), nil).Render(c.Context(), c)
}) })
app.Get("/discover", func(c *fiber.Ctx) error { app.Get("/discover", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -353,7 +433,7 @@ func main() {
log.Fatalln("failed to marshal info: ", err) log.Fatalln("failed to marshal info: ", err)
} }
app.Get("/_/info", func(c *fiber.Ctx) error { app.Get("/_/info", func(c fiber.Ctx) error {
c.Set("Content-Type", "application/json") c.Set("Content-Type", "application/json")
return c.Send(inf) return c.Send(inf)
}) })
@@ -365,7 +445,7 @@ func main() {
preferences.Load(app) preferences.Load(app)
app.Get("/_/searchSuggestions", func(c *fiber.Ctx) error { app.Get("/_/searchSuggestions", func(c fiber.Ctx) error {
q := c.Query("q") q := c.Query("q")
if q == "" { if q == "" {
return fiber.ErrBadRequest return fiber.ErrBadRequest
@@ -380,11 +460,11 @@ func main() {
}) })
// Currently, /:user is the tracks page // Currently, /:user is the tracks page
app.Get("/:user/tracks", func(c *fiber.Ctx) error { app.Get("/:user/tracks", func(c fiber.Ctx) error {
return c.Redirect("/" + c.Params("user")) return c.Redirect().To("/" + c.Params("user"))
}) })
app.Get("/:user/sets", func(c *fiber.Ctx) error { app.Get("/:user/sets", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -412,7 +492,7 @@ func main() {
return templates.Base(user.Username, templates.UserPlaylists(prefs, user, pl), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserPlaylists(prefs, user, pl), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/albums", func(c *fiber.Ctx) error { app.Get("/:user/albums", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -440,7 +520,7 @@ func main() {
return templates.Base(user.Username, templates.UserAlbums(prefs, user, pl), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserAlbums(prefs, user, pl), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/reposts", func(c *fiber.Ctx) error { app.Get("/:user/reposts", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -468,7 +548,7 @@ func main() {
return templates.Base(user.Username, templates.UserReposts(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserReposts(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/likes", func(c *fiber.Ctx) error { app.Get("/:user/likes", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -496,7 +576,7 @@ func main() {
return templates.Base(user.Username, templates.UserLikes(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserLikes(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/popular-tracks", func(c *fiber.Ctx) error { app.Get("/:user/popular-tracks", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -524,7 +604,7 @@ func main() {
return templates.Base(user.Username, templates.UserTopTracks(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserTopTracks(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/followers", func(c *fiber.Ctx) error { app.Get("/:user/followers", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -552,7 +632,7 @@ func main() {
return templates.Base(user.Username, templates.UserFollowers(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserFollowers(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/following", func(c *fiber.Ctx) error { app.Get("/:user/following", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -580,7 +660,7 @@ func main() {
return templates.Base(user.Username, templates.UserFollowing(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c) return templates.Base(user.Username, templates.UserFollowing(prefs, user, p), templates.UserHeader(user)).Render(c.Context(), c)
}) })
app.Get("/:user/:track", func(c *fiber.Ctx) error { app.Get("/:user/:track", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -674,7 +754,7 @@ func main() {
return templates.Base(track.Title+" by "+track.Author.Username, templates.Track(prefs, track, stream, displayErr, c.Query("autoplay") == "true", playlist, nextTrack, c.Query("volume"), mode, audio), templates.TrackHeader(prefs, track, true)).Render(c.Context(), c) return templates.Base(track.Title+" by "+track.Author.Username, templates.Track(prefs, track, stream, displayErr, c.Query("autoplay") == "true", playlist, nextTrack, c.Query("volume"), mode, audio), templates.TrackHeader(prefs, track, true)).Render(c.Context(), c)
}) })
app.Get("/:user", func(c *fiber.Ctx) error { app.Get("/:user", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -702,7 +782,7 @@ func main() {
return templates.Base(usr.Username, templates.User(prefs, usr, p), templates.UserHeader(usr)).Render(c.Context(), c) return templates.Base(usr.Username, templates.User(prefs, usr, p), templates.UserHeader(usr)).Render(c.Context(), c)
}) })
app.Get("/:user/sets/:playlist", func(c *fiber.Ctx) error { app.Get("/:user/sets/:playlist", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -742,7 +822,7 @@ func main() {
return templates.Base(playlist.Title+" by "+playlist.Author.Username, templates.Playlist(prefs, playlist), templates.PlaylistHeader(playlist)).Render(c.Context(), c) return templates.Base(playlist.Title+" by "+playlist.Author.Username, templates.Playlist(prefs, playlist), templates.PlaylistHeader(playlist)).Render(c.Context(), c)
}) })
app.Get("/:user/_/related", func(c *fiber.Ctx) error { app.Get("/:user/_/related", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -771,7 +851,7 @@ func main() {
}) })
// I'd like to make this "related" but keeping it "recommended" to have the same url as soundcloud // I'd like to make this "related" but keeping it "recommended" to have the same url as soundcloud
app.Get("/:user/:track/recommended", func(c *fiber.Ctx) error { app.Get("/:user/:track/recommended", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -799,7 +879,7 @@ func main() {
return templates.Base(track.Title+" by "+track.Author.Username, templates.RelatedTracks(track, r), templates.TrackHeader(prefs, track, false)).Render(c.Context(), c) return templates.Base(track.Title+" by "+track.Author.Username, templates.RelatedTracks(track, r), templates.TrackHeader(prefs, track, false)).Render(c.Context(), c)
}) })
app.Get("/:user/:track/sets", func(c *fiber.Ctx) error { app.Get("/:user/:track/sets", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -827,7 +907,7 @@ func main() {
return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInPlaylists(track, p), templates.TrackHeader(prefs, track, false)).Render(c.Context(), c) return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInPlaylists(track, p), templates.TrackHeader(prefs, track, false)).Render(c.Context(), c)
}) })
app.Get("/:user/:track/albums", func(c *fiber.Ctx) error { app.Get("/:user/:track/albums", func(c fiber.Ctx) error {
prefs, err := preferences.Get(c) prefs, err := preferences.Get(c)
if err != nil { if err != nil {
return err return err
@@ -858,5 +938,5 @@ func main() {
if cfg.CodegenConfig { if cfg.CodegenConfig {
log.Println("Warning: you have CodegenConfig enabled, but the config was loaded dynamically.") log.Println("Warning: you have CodegenConfig enabled, but the config was loaded dynamically.")
} }
log.Fatal(app.Listen(cfg.Addr)) log.Fatal(app.Listen(cfg.Addr, fiber.ListenConfig{EnablePrefork: cfg.Prefork}))
} }

View File

@@ -10,6 +10,7 @@ templ Base(title string, content templ.Component, head templ.Component) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="/_/static/global.css"/> <link rel="stylesheet" href="/_/static/global.css"/>
<link rel="stylesheet" href="/_/static/instance.css"/> <link rel="stylesheet" href="/_/static/instance.css"/>
<link rel="icon" href="/_/static/favicon.ico"/>
if title != "" { if title != "" {
<title>{ title } ~ soundcloak</title> <title>{ title } ~ soundcloak</title>
} else { } else {