mirror of
https://git.maid.zone/stuff/soundcloak.git
synced 2025-12-11 14:19:38 +05:00
Get links to other places in user profiles; other small improvements
This commit is contained in:
@@ -191,6 +191,7 @@ Some notes:
|
||||
| JSON key | Environment variable | Default value | Description |
|
||||
| :------------------------ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| None | SOUNDCLOAK_CONFIG | soundcloak.json | File to load soundcloak config from. If set to `FROM_ENV`, soundcloak loads the config from environment variables. |
|
||||
| GetWebProfiles | GET_WEB_PROFILES | true | Retrieve links users set in their profile (social media, website, etc) |
|
||||
| DefaultPreferences | DEFAULT_PREFERENCES | {"Player": "hls", "ProxyStreams": false, "FullyPreloadTrack": false, "ProxyImages": false, "ParseDescriptions": true} | see /_/preferences page, default values adapt to your config (Player: "restream" if Restream, else "hls", ProxyStreams and ProxyImages will be same as respective config values) |
|
||||
| ProxyImages | PROXY_IMAGES | false | Enables proxying of images (user avatars, track covers etc) |
|
||||
| ImageCacheControl | IMAGE_CACHE_CONTROL | max-age=600, public, immutable | [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) header value for proxied images. Cached for 10 minutes by default. |
|
||||
|
||||
@@ -160,4 +160,9 @@ select:focus {
|
||||
|
||||
.link {
|
||||
color: var(--accent);
|
||||
text-decoration: underline dashed;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -42,6 +42,9 @@ type Preferences struct {
|
||||
|
||||
// // config // //
|
||||
|
||||
// Retrieve links users set in their profile (social media, website, etc)
|
||||
var GetWebProfiles = true
|
||||
|
||||
// Default preferences. You can override those preferences in the config file, otherwise they default to values depending on your config
|
||||
// (so, if you have ProxyStreams enabled - it will be enabled for the user by default and etc, or if you enabled Restream, the default player will be RestreamPlayer instead of HLSPlayer)
|
||||
var DefaultPreferences Preferences
|
||||
@@ -189,7 +192,12 @@ func (w wrappedError) Error() string {
|
||||
}
|
||||
|
||||
func fromEnv() error {
|
||||
env := os.Getenv("DEFAULT_PREFERENCES")
|
||||
env := os.Getenv("GET_WEB_PROFILES")
|
||||
if env != "" {
|
||||
GetWebProfiles = boolean(env)
|
||||
}
|
||||
|
||||
env = os.Getenv("DEFAULT_PREFERENCES")
|
||||
if env != "" {
|
||||
var p Preferences
|
||||
err := json.Unmarshal([]byte(env), &p)
|
||||
@@ -372,6 +380,7 @@ func init() {
|
||||
}
|
||||
|
||||
var config struct {
|
||||
GetWebProfiles *bool
|
||||
DefaultPreferences *Preferences
|
||||
ProxyImages *bool
|
||||
ImageCacheControl *string
|
||||
@@ -403,6 +412,9 @@ func init() {
|
||||
|
||||
// tedious
|
||||
// i've decided to fully override to make it easier to change default config later on
|
||||
if config.GetWebProfiles != nil {
|
||||
GetWebProfiles = *config.GetWebProfiles
|
||||
}
|
||||
if config.ProxyImages != nil {
|
||||
ProxyImages = *config.ProxyImages
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ func GetFeaturedTracks(prefs cfg.Preferences, args string) (*Paginated[*Track],
|
||||
}
|
||||
|
||||
for _, t := range p.Collection {
|
||||
t.Fix(false)
|
||||
t.Postfix(prefs)
|
||||
t.Fix(false, false)
|
||||
t.Postfix(prefs, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
@@ -55,7 +55,7 @@ func GetSelections(prefs cfg.Preferences) (*Paginated[*Selection], error) {
|
||||
|
||||
func (s *Selection) Fix(prefs cfg.Preferences) {
|
||||
for _, p := range s.Items.Collection {
|
||||
p.Fix(false)
|
||||
p.Postfix(prefs, false)
|
||||
p.Fix(false, false)
|
||||
p.Postfix(prefs, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func GetPlaylist(permalink string) (Playlist, error) {
|
||||
return p, ErrKindNotCorrect
|
||||
}
|
||||
|
||||
err = p.Fix(true)
|
||||
err = p.Fix(true, true)
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
@@ -78,45 +78,50 @@ func SearchPlaylists(prefs cfg.Preferences, args string) (*Paginated[*Playlist],
|
||||
}
|
||||
|
||||
for _, p := range p.Collection {
|
||||
p.Fix(false)
|
||||
p.Postfix(prefs, false)
|
||||
p.Fix(false, false)
|
||||
p.Postfix(prefs, false, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (p *Playlist) Fix(cached bool) error {
|
||||
func (p *Playlist) Fix(cached bool, fixAuthor bool) error {
|
||||
if cached {
|
||||
for i, t := range p.Tracks {
|
||||
t.Fix(false)
|
||||
p.Tracks[i] = t
|
||||
}
|
||||
|
||||
err := p.GetMissingTracks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, t := range p.Tracks {
|
||||
t.Fix(false, false)
|
||||
p.Tracks[i] = t
|
||||
}
|
||||
|
||||
p.Artwork = strings.Replace(p.Artwork, "-large.", "-t500x500.", 1)
|
||||
} else {
|
||||
p.Artwork = strings.Replace(p.Artwork, "-large.", "-t200x200.", 1)
|
||||
}
|
||||
|
||||
if fixAuthor {
|
||||
p.Author.Fix(false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Playlist) Postfix(prefs cfg.Preferences, fixTracks bool) []Track {
|
||||
func (p *Playlist) Postfix(prefs cfg.Preferences, fixTracks bool, fixAuthor bool) []Track {
|
||||
if cfg.ProxyImages && *prefs.ProxyImages && p.Artwork != "" {
|
||||
p.Artwork = "/_/proxy/images?url=" + url.QueryEscape(p.Artwork)
|
||||
}
|
||||
|
||||
if fixAuthor {
|
||||
p.Author.Postfix(prefs)
|
||||
}
|
||||
|
||||
if fixTracks {
|
||||
var fixed = make([]Track, len(p.Tracks))
|
||||
for i, t := range p.Tracks {
|
||||
t.Postfix(prefs)
|
||||
t.Postfix(prefs, false)
|
||||
fixed[i] = t
|
||||
}
|
||||
return fixed
|
||||
|
||||
@@ -108,7 +108,7 @@ func GetTrack(permalink string) (Track, error) {
|
||||
return t, ErrKindNotCorrect
|
||||
}
|
||||
|
||||
t.Fix(true)
|
||||
t.Fix(true, true)
|
||||
|
||||
tracksCacheLock.Lock()
|
||||
TracksCache[permalink] = cached[Track]{Value: t, Expires: time.Now().Add(cfg.TrackTTL)}
|
||||
@@ -217,8 +217,8 @@ func SearchTracks(prefs cfg.Preferences, args string) (*Paginated[*Track], error
|
||||
}
|
||||
|
||||
for _, t := range p.Collection {
|
||||
t.Fix(false)
|
||||
t.Postfix(prefs)
|
||||
t.Fix(false, false)
|
||||
t.Postfix(prefs, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
@@ -253,7 +253,7 @@ func GetTracks(ids string) ([]Track, error) {
|
||||
var res []Track
|
||||
err = json.Unmarshal(data, &res)
|
||||
for i, t := range res {
|
||||
t.Fix(false)
|
||||
t.Fix(false, false)
|
||||
res[i] = t
|
||||
}
|
||||
return res, err
|
||||
@@ -306,7 +306,7 @@ func (tr Transcoding) GetStream(prefs cfg.Preferences, authorization string) (st
|
||||
return s.URL, nil
|
||||
}
|
||||
|
||||
func (t *Track) Fix(large bool) {
|
||||
func (t *Track) Fix(large bool, fixAuthor bool) {
|
||||
if large {
|
||||
t.Artwork = strings.Replace(t.Artwork, "-large.", "-t500x500.", 1)
|
||||
} else {
|
||||
@@ -320,15 +320,20 @@ func (t *Track) Fix(large bool) {
|
||||
t.ID = ls[len(ls)-1]
|
||||
}
|
||||
|
||||
if fixAuthor {
|
||||
t.Author.Fix(false)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Track) Postfix(prefs cfg.Preferences) {
|
||||
func (t *Track) Postfix(prefs cfg.Preferences, fixAuthor bool) {
|
||||
if cfg.ProxyImages && *prefs.ProxyImages && t.Artwork != "" {
|
||||
t.Artwork = "/_/proxy/images?url=" + url.QueryEscape(t.Artwork)
|
||||
}
|
||||
|
||||
if fixAuthor {
|
||||
t.Author.Postfix(prefs)
|
||||
}
|
||||
}
|
||||
|
||||
func (t Track) FormatDescription() string {
|
||||
desc := t.Description
|
||||
@@ -394,7 +399,7 @@ func GetTrackByID(id string) (Track, error) {
|
||||
return t, ErrKindNotCorrect
|
||||
}
|
||||
|
||||
t.Fix(true)
|
||||
t.Fix(true, true)
|
||||
|
||||
tracksCacheLock.Lock()
|
||||
TracksCache[t.Author.Permalink+"/"+t.Permalink] = cached[Track]{Value: t, Expires: time.Now().Add(cfg.TrackTTL)}
|
||||
|
||||
105
lib/sc/user.go
105
lib/sc/user.go
@@ -1,6 +1,7 @@
|
||||
package sc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -8,6 +9,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/maid-zone/soundcloak/lib/cfg"
|
||||
"github.com/maid-zone/soundcloak/lib/textparsing"
|
||||
"github.com/segmentio/encoding/json"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// Functions/structures related to users
|
||||
@@ -31,6 +35,13 @@ type User struct {
|
||||
ID string `json:"urn"`
|
||||
Username string `json:"username"`
|
||||
Verified bool `json:"verified"`
|
||||
|
||||
WebProfiles []Link
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
URL string `json:"url"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type RepostType string
|
||||
@@ -52,14 +63,14 @@ func (r Repost) Fix(prefs cfg.Preferences) {
|
||||
switch r.Type {
|
||||
case TrackRepost:
|
||||
if r.Track != nil {
|
||||
r.Track.Fix(false)
|
||||
r.Track.Postfix(prefs)
|
||||
r.Track.Fix(false, false)
|
||||
r.Track.Postfix(prefs, false)
|
||||
}
|
||||
return
|
||||
case PlaylistRepost:
|
||||
if r.Playlist != nil {
|
||||
r.Playlist.Fix(false) // err always nil if cached == false
|
||||
r.Playlist.Postfix(prefs, false)
|
||||
r.Playlist.Fix(false, false) // err always nil if cached == false
|
||||
r.Playlist.Postfix(prefs, false, false)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -73,11 +84,11 @@ type Like struct {
|
||||
|
||||
func (l Like) Fix(prefs cfg.Preferences) {
|
||||
if l.Track != nil {
|
||||
l.Track.Fix(false)
|
||||
l.Track.Postfix(prefs)
|
||||
l.Track.Fix(false, false)
|
||||
l.Track.Postfix(prefs, false)
|
||||
} else if l.Playlist != nil {
|
||||
l.Playlist.Fix(false)
|
||||
l.Playlist.Postfix(prefs, false)
|
||||
l.Playlist.Fix(false, false)
|
||||
l.Playlist.Postfix(prefs, false, false)
|
||||
}
|
||||
}
|
||||
func GetUser(permalink string) (User, error) {
|
||||
@@ -100,6 +111,12 @@ func GetUser(permalink string) (User, error) {
|
||||
return u, err
|
||||
}
|
||||
|
||||
if cfg.GetWebProfiles {
|
||||
err = u.GetWebProfiles()
|
||||
if err != nil {
|
||||
return u, err
|
||||
}
|
||||
}
|
||||
u.Fix(true)
|
||||
|
||||
usersCacheLock.Lock()
|
||||
@@ -140,8 +157,8 @@ func (u User) GetTracks(prefs cfg.Preferences, args string) (*Paginated[*Track],
|
||||
}
|
||||
|
||||
for _, t := range p.Collection {
|
||||
t.Fix(false)
|
||||
t.Postfix(prefs)
|
||||
t.Fix(false, false)
|
||||
t.Postfix(prefs, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
@@ -184,6 +201,25 @@ func (u *User) Fix(large bool) {
|
||||
|
||||
ls := strings.Split(u.ID, ":")
|
||||
u.ID = ls[len(ls)-1]
|
||||
|
||||
for i, l := range u.WebProfiles {
|
||||
if textparsing.IsEmail(l.URL) {
|
||||
l.URL = "mailto:" + l.URL
|
||||
u.WebProfiles[i] = l
|
||||
} else {
|
||||
parsed, err := url.Parse(l.URL)
|
||||
if err == nil {
|
||||
if parsed.Host == "soundcloud.com" || strings.HasSuffix(parsed.Host, ".soundcloud.com") {
|
||||
l.URL = "/" + strings.Join(strings.Split(l.URL, "/")[3:], "/")
|
||||
if parsed.Host == "on.soundcloud.com" {
|
||||
l.URL = "/on" + l.URL
|
||||
}
|
||||
|
||||
u.WebProfiles[i] = l
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) Postfix(prefs cfg.Preferences) {
|
||||
@@ -192,7 +228,7 @@ func (u *User) Postfix(prefs cfg.Preferences) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) GetPlaylists(prefs cfg.Preferences, args string) (*Paginated[*Playlist], error) {
|
||||
func (u User) GetPlaylists(prefs cfg.Preferences, args string) (*Paginated[*Playlist], error) {
|
||||
p := Paginated[*Playlist]{
|
||||
Next: "https://" + api + "/users/" + u.ID + "/playlists_without_albums" + args,
|
||||
}
|
||||
@@ -203,14 +239,14 @@ func (u *User) GetPlaylists(prefs cfg.Preferences, args string) (*Paginated[*Pla
|
||||
}
|
||||
|
||||
for _, pl := range p.Collection {
|
||||
pl.Fix(false)
|
||||
pl.Postfix(prefs, false)
|
||||
pl.Fix(false, false)
|
||||
pl.Postfix(prefs, false, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (u *User) GetAlbums(prefs cfg.Preferences, args string) (*Paginated[*Playlist], error) {
|
||||
func (u User) GetAlbums(prefs cfg.Preferences, args string) (*Paginated[*Playlist], error) {
|
||||
p := Paginated[*Playlist]{
|
||||
Next: "https://" + api + "/users/" + u.ID + "/albums" + args,
|
||||
}
|
||||
@@ -221,14 +257,14 @@ func (u *User) GetAlbums(prefs cfg.Preferences, args string) (*Paginated[*Playli
|
||||
}
|
||||
|
||||
for _, pl := range p.Collection {
|
||||
pl.Fix(false)
|
||||
pl.Postfix(prefs, false)
|
||||
pl.Fix(false, false)
|
||||
pl.Postfix(prefs, false, false)
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (u *User) GetReposts(prefs cfg.Preferences, args string) (*Paginated[*Repost], error) {
|
||||
func (u User) GetReposts(prefs cfg.Preferences, args string) (*Paginated[*Repost], error) {
|
||||
p := Paginated[*Repost]{
|
||||
Next: "https://" + api + "/stream/users/" + u.ID + "/reposts" + args,
|
||||
}
|
||||
@@ -245,7 +281,7 @@ func (u *User) GetReposts(prefs cfg.Preferences, args string) (*Paginated[*Repos
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (u *User) GetLikes(prefs cfg.Preferences, args string) (*Paginated[*Like], error) {
|
||||
func (u User) GetLikes(prefs cfg.Preferences, args string) (*Paginated[*Like], error) {
|
||||
p := Paginated[*Like]{
|
||||
Next: "https://" + api + "/users/" + u.ID + "/likes" + args,
|
||||
}
|
||||
@@ -261,3 +297,36 @@ func (u *User) GetLikes(prefs cfg.Preferences, args string) (*Paginated[*Like],
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (u *User) GetWebProfiles() error {
|
||||
cid, err := GetClientID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(req)
|
||||
|
||||
req.SetRequestURI("https://" + api + "/users/" + u.ID + "/web-profiles?client_id=" + cid)
|
||||
req.Header.Set("User-Agent", cfg.UserAgent)
|
||||
req.Header.Set("Accept-Encoding", "gzip, deflate, br, zstd")
|
||||
|
||||
resp := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(resp)
|
||||
|
||||
err = DoWithRetry(httpc, req, resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != 200 {
|
||||
return fmt.Errorf("getwebprofiles: got status code %d", resp.StatusCode())
|
||||
}
|
||||
|
||||
data, err := resp.BodyUncompressed()
|
||||
if err != nil {
|
||||
data = resp.Body()
|
||||
}
|
||||
|
||||
return json.Unmarshal(data, &u.WebProfiles)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,15 @@ import (
|
||||
//var wordre = regexp.MustCompile(`\S+`)
|
||||
|
||||
// var urlre = regexp.MustCompile(`https?:\/\/[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{1,6}[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*`)
|
||||
// var emailre = regexp.MustCompile(`[-a-zA-Z0-9%._\+~#=]+@[-a-zA-Z0-9%._\+~=&]{2,256}\.[a-z]{1,6}`)
|
||||
var emailre = regexp.MustCompile(`^[-a-zA-Z0-9%._\+~#=]+@[-a-zA-Z0-9%._\+~=&]{2,256}\.[a-z]{1,6}$`)
|
||||
|
||||
// var usernamere = regexp.MustCompile(`@[a-zA-Z0-9\-]+`)
|
||||
var theregex = regexp.MustCompile(`@[a-zA-Z0-9\-]+|(?:https?:\/\/[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{1,6}[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)|(?:[-a-zA-Z0-9%._\+~#=]+@[-a-zA-Z0-9%._\+~=&]{2,256}\.[a-z]{1,6})`)
|
||||
|
||||
func IsEmail(s string) bool {
|
||||
return emailre.MatchString(s)
|
||||
}
|
||||
|
||||
func replacer(ent string) string {
|
||||
if strings.HasPrefix(ent, "@") {
|
||||
return fmt.Sprintf(`<a class="link" href="/%s">%s</a>`, ent[1:], ent)
|
||||
@@ -27,6 +32,9 @@ func replacer(ent string) string {
|
||||
href := ent
|
||||
if parsed.Host == "soundcloud.com" || strings.HasSuffix(parsed.Host, ".soundcloud.com") {
|
||||
href = "/" + strings.Join(strings.Split(ent, "/")[3:], "/")
|
||||
if parsed.Host == "on.soundcloud.com" {
|
||||
href = "/on" + href
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`<a class="link" href="%s" referrerpolicy="no-referrer" rel="external nofollow noopener noreferrer ugc" target="_blank">%s</a>`, href, ent)
|
||||
|
||||
8
main.go
8
main.go
@@ -152,7 +152,7 @@ func main() {
|
||||
log.Printf("error getting %s: %s\n", u, err)
|
||||
return err
|
||||
}
|
||||
track.Postfix(prefs)
|
||||
track.Postfix(prefs, true)
|
||||
|
||||
displayErr := ""
|
||||
stream := ""
|
||||
@@ -344,7 +344,7 @@ func main() {
|
||||
log.Printf("error getting %s from %s: %s\n", c.Params("track"), c.Params("user"), err)
|
||||
return err
|
||||
}
|
||||
track.Postfix(prefs)
|
||||
track.Postfix(prefs, true)
|
||||
|
||||
displayErr := ""
|
||||
stream := ""
|
||||
@@ -408,7 +408,7 @@ func main() {
|
||||
return err
|
||||
}
|
||||
// Don't ask why
|
||||
playlist.Tracks = playlist.Postfix(prefs, true)
|
||||
playlist.Tracks = playlist.Postfix(prefs, true, true)
|
||||
|
||||
p := c.Query("pagination")
|
||||
if p != "" {
|
||||
@@ -419,7 +419,7 @@ func main() {
|
||||
}
|
||||
|
||||
for i, track := range tracks {
|
||||
track.Postfix(prefs)
|
||||
track.Postfix(prefs, false)
|
||||
tracks[i] = track
|
||||
}
|
||||
|
||||
|
||||
@@ -28,15 +28,22 @@ templ Base(title string, content templ.Component, head templ.Component) {
|
||||
</html>
|
||||
}
|
||||
|
||||
templ Description(prefs cfg.Preferences, text string) {
|
||||
templ Description(prefs cfg.Preferences, text string, injected templ.Component) {
|
||||
if text != "" || injected != nil {
|
||||
<details>
|
||||
<summary>Toggle description</summary>
|
||||
<p style="white-space: pre-wrap;">
|
||||
if text != "" {
|
||||
if *prefs.ParseDescriptions {
|
||||
@templ.Raw(textparsing.Format(text))
|
||||
} else {
|
||||
{ text }
|
||||
}
|
||||
}
|
||||
if injected != nil {
|
||||
@injected
|
||||
}
|
||||
</p>
|
||||
</details>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"github.com/maid-zone/soundcloak/lib/cfg"
|
||||
"github.com/maid-zone/soundcloak/lib/sc"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"github.com/maid-zone/soundcloak/lib/cfg"
|
||||
)
|
||||
|
||||
templ PlaylistHeader(p sc.Playlist) {
|
||||
@@ -43,9 +43,7 @@ templ Playlist(prefs cfg.Preferences, p sc.Playlist) {
|
||||
<a class="btn" href={ templ.URL("https://soundcloud.com/" + p.Author.Permalink + "/sets/" + p.Permalink) }>view on soundcloud</a>
|
||||
</div>
|
||||
<br/>
|
||||
if p.Description != "" {
|
||||
@Description(prefs, p.Description)
|
||||
}
|
||||
@Description(prefs, p.Description, nil)
|
||||
<p>{ strconv.FormatInt(p.TrackCount, 10) } tracks</p>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
@@ -23,7 +23,6 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
if *prefs.Player == cfg.NonePlayer {
|
||||
{{ return }}
|
||||
}
|
||||
|
||||
if displayErr == "" {
|
||||
if cfg.Restream && *prefs.Player == cfg.RestreamPlayer {
|
||||
<audio src={ "/_/restream/" + track.Author.Permalink + "/" + track.Permalink } controls></audio>
|
||||
@@ -38,7 +37,7 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
<br/>
|
||||
JavaScript is disabled! Audio playback may not work without it enabled.
|
||||
if cfg.Restream {
|
||||
<br>
|
||||
<br/>
|
||||
<a class="link" href="/_/preferences">You can enable Restream player in the preferences. It works without JavaScript.</a>
|
||||
}
|
||||
</noscript>
|
||||
@@ -89,9 +88,7 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string)
|
||||
}
|
||||
</div>
|
||||
<br/>
|
||||
if t.Description != "" {
|
||||
@Description(prefs, t.Description)
|
||||
}
|
||||
@Description(prefs, t.Description, nil)
|
||||
<p>{ strconv.FormatInt(t.Likes, 10) } likes</p>
|
||||
<p>{ strconv.FormatInt(t.Played, 10) } plays</p>
|
||||
<p>{ strconv.FormatInt(t.Reposted, 10) } reposts</p>
|
||||
|
||||
@@ -32,6 +32,18 @@ templ UserItem(user *sc.User) {
|
||||
</a>
|
||||
}
|
||||
|
||||
templ UserLinks(links []sc.Link) {
|
||||
for _, link := range links {
|
||||
if len(link.URL) > 0 {
|
||||
if link.URL[0] == '/' {
|
||||
<p><a class="link" href={ templ.URL(link.URL) }>- { link.Title }</a></p>
|
||||
} else {
|
||||
<p><a class="link" href={ templ.URL(link.URL) } referrerpolicy="no-referrer" rel="external nofollow noopener noreferrer" target="_blank">- { link.Title }</a></p>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
templ UserBase(prefs cfg.Preferences, u sc.User) {
|
||||
<div>
|
||||
if u.Avatar != "" {
|
||||
@@ -45,8 +57,10 @@ templ UserBase(prefs cfg.Preferences, u sc.User) {
|
||||
<p style="color: var(--accent)">Verified</p>
|
||||
}
|
||||
</div>
|
||||
if u.Description != "" {
|
||||
@Description(prefs, u.Description)
|
||||
if len(u.WebProfiles) != 0 {
|
||||
@Description(prefs, u.Description, UserLinks(u.WebProfiles))
|
||||
} else {
|
||||
@Description(prefs, u.Description, nil)
|
||||
}
|
||||
<div>
|
||||
<p>{ strconv.FormatInt(u.Followers, 10) } followers</p>
|
||||
@@ -66,7 +80,8 @@ type btn struct {
|
||||
}
|
||||
|
||||
templ UserButtons(current string, user string) {
|
||||
<div class="btns"> // this part is the tedious one now, because formatting breaks if i space the list out with newlines
|
||||
<div class="btns">
|
||||
// this part is the tedious one now, because formatting breaks if i space the list out with newlines
|
||||
for _, b := range [6]btn{{"tracks", "", false},{"playlists", "/sets",false},{"albums", "/albums", false},{"reposts","/reposts", false},{"likes", "/likes", false},{"view on soundcloud", "https://soundcloud.com/"+user, true}} {
|
||||
if b.text == current {
|
||||
<a class="btn active">{ b.text }</a>
|
||||
|
||||
Reference in New Issue
Block a user