diff --git a/assets/global.css b/assets/global.css
index b765933..6ab5b6d 100644
--- a/assets/global.css
+++ b/assets/global.css
@@ -133,14 +133,6 @@ details > summary:hover {
width: fit-content;
}
-footer {
- margin-top: 5rem;
- gap: 1rem;
- display: grid;
- grid-template: auto / auto auto auto;
- justify-content: center;
-}
-
select {
background: var(--secondary);
border-color: var(--0);
diff --git a/assets/index.css b/assets/index.css
new file mode 100644
index 0000000..5d9893e
--- /dev/null
+++ b/assets/index.css
@@ -0,0 +1,26 @@
+#search-suggestions {
+ list-style: none;
+ position: absolute;
+ background-color: var(--secondary);
+ margin: 0;
+ padding: 1rem;
+ padding-bottom: 0;
+ /* god damn this shit i hate webdev */
+ width: 100%;
+ width: -moz-available;
+ width: -webkit-fill-available;
+ width: stretch;
+ width: fill-available;
+}
+
+#search-suggestions > li {
+ padding-bottom: 1rem;
+}
+
+footer {
+ margin-top: 5rem;
+ gap: 1rem;
+ display: grid;
+ grid-template: auto / auto auto auto;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/assets/index.html b/assets/index.html
deleted file mode 100644
index 1f6661f..0000000
--- a/assets/index.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
- soundcloak
-
-
-
-
-
- soundcloak
-
-
-
-
-
\ No newline at end of file
diff --git a/assets/index.js b/assets/index.js
new file mode 100644
index 0000000..3acda8a
--- /dev/null
+++ b/assets/index.js
@@ -0,0 +1,55 @@
+var searchSuggestions = document.getElementById('search-suggestions');
+var input = document.getElementById('q');
+var timeout;
+
+function getSuggestions() {
+ if (input.value == 0) {
+ searchSuggestions.style.display = 'none';
+ return;
+ }
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', '/_/searchSuggestions?q=' + encodeURIComponent(input.value), true);
+ xhr.onload = function () {
+ try {
+ var cloned = searchSuggestions.cloneNode(false);
+
+ var data = JSON.parse(xhr.responseText);
+ if (data.length == 0) {
+ searchSuggestions.style.display = 'none';
+ return;
+ }
+
+ for (var i = 0; i < data.length; i++) {
+ var e = document.createElement('li');
+ e.textContent = data[i];
+ e.onclick = function () {
+ input.value = this.textContent;
+ searchSuggestions.style.display = 'none';
+ }
+ cloned.appendChild(e);
+ }
+
+ searchSuggestions.parentNode.replaceChild(cloned, searchSuggestions);
+ searchSuggestions = cloned;
+ searchSuggestions.style.display = 'block';
+ } catch {
+ searchSuggestions.style.display = 'none';
+ }
+ }
+
+ xhr.onerror = function () {
+ searchSuggestions.style.display = 'none';
+ }
+
+ xhr.send();
+}
+
+input.addEventListener('input', function () {
+ if (!timeout) {
+ timeout = setTimeout(getSuggestions, 250);
+ } else {
+ clearTimeout(timeout);
+ timeout = setTimeout(getSuggestions, 250);
+ }
+});
\ No newline at end of file
diff --git a/lib/cfg/init.go b/lib/cfg/init.go
index be9a88f..8b31e02 100644
--- a/lib/cfg/init.go
+++ b/lib/cfg/init.go
@@ -99,6 +99,10 @@ var CodegenConfig = false
// ParseDescriptions: true
// AutoplayNextTrack: false
// DefaultAutoplayMode: AutoplayNormal
+// HLSAudio: AudioMP3
+// RestreamAudio: AudioMP3
+// DownloadAudio: AudioMP3
+// ShowAudio: false
func defaultPreferences() {
var p string
if Restream {
@@ -126,6 +130,8 @@ func defaultPreferences() {
DefaultPreferences.DownloadAudio = &p3
DefaultPreferences.ShowAudio = &False
+
+ DefaultPreferences.SearchSuggestions = &False
}
func loadDefaultPreferences(loaded Preferences) {
@@ -202,6 +208,12 @@ func loadDefaultPreferences(loaded Preferences) {
} else {
DefaultPreferences.ShowAudio = &False
}
+
+ if loaded.SearchSuggestions != nil {
+ DefaultPreferences.SearchSuggestions = loaded.SearchSuggestions
+ } else {
+ DefaultPreferences.SearchSuggestions = &False
+ }
}
func boolean(in string) bool {
diff --git a/lib/cfg/misc.go b/lib/cfg/misc.go
index dfbf3bd..b75b697 100644
--- a/lib/cfg/misc.go
+++ b/lib/cfg/misc.go
@@ -58,11 +58,13 @@ type Preferences struct {
DefaultAutoplayMode *string // "normal" or "random"
- // Check line 38 for constants
+ // Check above for more info
// Probably best to keep all at "mpeg" by default for compatibility
HLSAudio *string // Please don't use "opus" or "best". hls.js doesn't work with ogg/opus
RestreamAudio *string // You can actually use anything here
DownloadAudio *string // "aac" may not play well with some players
ShowAudio *bool // display audio (aac, opus, mpeg etc) under track player
+
+ SearchSuggestions *bool // load search suggestions on main page
}
diff --git a/lib/preferences/init.go b/lib/preferences/init.go
index 61fe159..65914d0 100644
--- a/lib/preferences/init.go
+++ b/lib/preferences/init.go
@@ -55,6 +55,10 @@ func Defaults(dst *cfg.Preferences) {
if dst.ShowAudio == nil {
dst.ShowAudio = cfg.DefaultPreferences.ShowAudio
}
+
+ if dst.SearchSuggestions == nil {
+ dst.SearchSuggestions = cfg.DefaultPreferences.SearchSuggestions
+ }
}
func Get(c *fiber.Ctx) (cfg.Preferences, error) {
@@ -82,6 +86,7 @@ type PrefsForm struct {
RestreamAudio string
DownloadAudio string
ShowAudio string
+ SearchSuggestions string
}
type Export struct {
@@ -167,6 +172,12 @@ func Load(r fiber.Router) {
old.ParseDescriptions = &cfg.False
}
+ if p.SearchSuggestions == "on" {
+ old.SearchSuggestions = &cfg.True
+ } else {
+ old.SearchSuggestions = &cfg.False
+ }
+
old.Player = &p.Player
data, err := json.Marshal(old)
diff --git a/lib/sc/init.go b/lib/sc/init.go
index 75be33a..fe0210b 100644
--- a/lib/sc/init.go
+++ b/lib/sc/init.go
@@ -408,6 +408,25 @@ func TagListParser(taglist string) (res []string) {
return
}
+type SearchSuggestion struct {
+ Query string `json:"query"`
+}
+
+func GetSearchSuggestions(cid string, query string) ([]string, error) {
+ p := Paginated[SearchSuggestion]{Next: "https://" + api + "/search/queries?limit=10&q=" + url.QueryEscape(query)}
+ err := p.Proceed(cid, false)
+ if err != nil {
+ return nil, err
+ }
+
+ l := make([]string, len(p.Collection)) // just so the response is a bit smaller, why not
+ for i, r := range p.Collection {
+ l[i] = r.Query
+ }
+
+ return l, nil
+}
+
// could probably make a generic function, whatever
func init() {
go func() {
diff --git a/main.go b/main.go
index 5207e79..2d98b28 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,6 @@
package main
import (
- "context"
"log"
"math/rand"
"net/url"
@@ -65,6 +64,21 @@ func main() {
})
}
+ {
+ mainPageHandler := func(c *fiber.Ctx) error {
+ prefs, err := preferences.Get(c)
+ if err != nil {
+ return err
+ }
+
+ c.Set("Content-Type", "text/html")
+ return templates.Base("", templates.MainPage(prefs), templates.MainPageHead()).Render(c.Context(), c)
+ }
+
+ app.Get("/", mainPageHandler)
+ app.Get("/index.html", mainPageHandler)
+ }
+
app.Get("/search", func(c *fiber.Ctx) error {
prefs, err := preferences.Get(c)
if err != nil {
@@ -82,7 +96,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("tracks: "+q, templates.SearchTracks(p), nil).Render(context.Background(), c)
+ return templates.Base("tracks: "+q, templates.SearchTracks(p), nil).Render(c.Context(), c)
case "users":
p, err := sc.SearchUsers("", prefs, c.Query("pagination", "?q="+url.QueryEscape(q)))
@@ -92,7 +106,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("users: "+q, templates.SearchUsers(p), nil).Render(context.Background(), c)
+ return templates.Base("users: "+q, templates.SearchUsers(p), nil).Render(c.Context(), c)
case "playlists":
p, err := sc.SearchPlaylists("", prefs, c.Query("pagination", "?q="+url.QueryEscape(q)))
@@ -102,7 +116,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("playlists: "+q, templates.SearchPlaylists(p), nil).Render(context.Background(), c)
+ return templates.Base("playlists: "+q, templates.SearchPlaylists(p), nil).Render(c.Context(), c)
}
return c.SendStatus(404)
@@ -197,7 +211,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.TrackEmbed(prefs, track, stream, displayErr).Render(context.Background(), c)
+ return templates.TrackEmbed(prefs, track, stream, displayErr).Render(c.Context(), c)
})
app.Get("/tags/:tag", func(c *fiber.Ctx) error {
@@ -219,7 +233,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("Recent tracks tagged "+tag, templates.RecentTracks(tag, p), nil).Render(context.Background(), 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 {
@@ -241,7 +255,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("Popular tracks tagged "+tag, templates.PopularTracks(tag, p), nil).Render(context.Background(), 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 {
@@ -264,7 +278,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("Playlists tagged "+tag, templates.TaggedPlaylists(tag, p), nil).Render(context.Background(), c)
+ return templates.Base("Playlists tagged "+tag, templates.TaggedPlaylists(tag, p), nil).Render(c.Context(), c)
})
app.Get("/_/featured", func(c *fiber.Ctx) error {
@@ -280,7 +294,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("Featured Tracks", templates.FeaturedTracks(tracks), nil).Render(context.Background(), c)
+ return templates.Base("Featured Tracks", templates.FeaturedTracks(tracks), nil).Render(c.Context(), c)
})
app.Get("/discover", func(c *fiber.Ctx) error {
@@ -296,7 +310,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base("Discover", templates.Discover(selections), nil).Render(context.Background(), c)
+ return templates.Base("Discover", templates.Discover(selections), nil).Render(c.Context(), c)
})
if cfg.ProxyImages {
@@ -337,6 +351,20 @@ func main() {
preferences.Load(app)
+ app.Get("/_/searchSuggestions", func(c *fiber.Ctx) error {
+ q := c.Query("q")
+ if q == "" {
+ return fiber.ErrBadRequest
+ }
+
+ s, err := sc.GetSearchSuggestions("", q)
+ if err != nil {
+ return err
+ }
+
+ return c.JSON(s)
+ })
+
// Currently, /:user is the tracks page
app.Get("/:user/tracks", func(c *fiber.Ctx) error {
return c.Redirect("/" + c.Params("user"))
@@ -367,7 +395,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserPlaylists(prefs, user, pl), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -395,7 +423,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserAlbums(prefs, user, pl), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -423,7 +451,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserReposts(prefs, user, p), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -451,7 +479,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserLikes(prefs, user, p), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -479,7 +507,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserTopTracks(prefs, user, p), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -507,7 +535,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserFollowers(prefs, user, p), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -535,7 +563,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserFollowing(prefs, user, p), templates.UserHeader(user)).Render(context.Background(), 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 {
@@ -629,7 +657,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- 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(context.Background(), 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 {
@@ -657,7 +685,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(usr.Username, templates.User(prefs, usr, p), templates.UserHeader(usr)).Render(context.Background(), 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 {
@@ -697,7 +725,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(playlist.Title+" by "+playlist.Author.Username, templates.Playlist(prefs, playlist), templates.PlaylistHeader(playlist)).Render(context.Background(), 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 {
@@ -725,7 +753,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(user.Username, templates.UserRelated(prefs, user, r), templates.UserHeader(user)).Render(context.Background(), c)
+ return templates.Base(user.Username, templates.UserRelated(prefs, user, r), templates.UserHeader(user)).Render(c.Context(), c)
})
// I'd like to make this "related" but keeping it "recommended" to have the same url as soundcloud
@@ -754,7 +782,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(track.Title+" by "+track.Author.Username, templates.RelatedTracks(track, r), templates.TrackHeader(prefs, track, false)).Render(context.Background(), 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 {
@@ -782,7 +810,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInPlaylists(track, p), templates.TrackHeader(prefs, track, false)).Render(context.Background(), 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 {
@@ -810,7 +838,7 @@ func main() {
}
c.Set("Content-Type", "text/html")
- return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInAlbums(track, p), templates.TrackHeader(prefs, track, false)).Render(context.Background(), c)
+ return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInAlbums(track, p), templates.TrackHeader(prefs, track, false)).Render(c.Context(), c)
})
if cfg.CodegenConfig {
diff --git a/templates/base.templ b/templates/base.templ
index 30d9fdf..a25337c 100644
--- a/templates/base.templ
+++ b/templates/base.templ
@@ -1,9 +1,6 @@
package templates
-import (
- "git.maid.zone/stuff/soundcloak/lib/cfg"
- "git.maid.zone/stuff/soundcloak/lib/textparsing"
-)
+import "git.maid.zone/stuff/soundcloak/lib/cfg"
templ Base(title string, content templ.Component, head templ.Component) {
@@ -32,22 +29,35 @@ templ Base(title string, content templ.Component, head templ.Component) {