mirror of
https://git.maid.zone/stuff/soundcloak.git
synced 2025-12-10 05:39:38 +05:00
option to autoplay a related track
This commit is contained in:
@@ -3,15 +3,16 @@
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :--------------------------------- | --------------------- | ------------------------------------------------------------------------ | ------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Parse descriptions | ParseDescriptions | true | true, false | Turn @mentions, external links (https://example.org) and emails (hello@example.org) inside descriptions into clickable links |
|
||||
| Show current audio | ShowAudio | false | true, false | Show what [audio preset](AUDIO_PRESETS.md) is being streamed below the audio player |
|
||||
| Proxy images | ProxyImages | same as ProxyImages in backend config | true, false | Proxy images through the backend. ProxyImages must be enabled on the backend |
|
||||
| Download audio | DownloadAudio | "mpeg" | "mpeg", "opus", "aac", "best" | What [audio preset](AUDIO_PRESETS.md) should be loaded when downloading audio with metadata. Restream must be enabled on the backend |
|
||||
| Autoplay next track in playlists | AutoplayNextTrack | false | true, false | Automatically start playlist playback when you open a track from the playlist. Requires JS |
|
||||
| Default autoplay mode | DefaultAutoplayMode | "normal" | "normal", "random" | Default mode for autoplay. Normal - play songs in order. Random - play random song next |
|
||||
| Fetch search suggestions | SearchSuggestions | false | true, false | Load search suggestions on main page when you type. Requires JS |
|
||||
| Dynamically load comments | DynamicLoadComments | false | true, false | Dynamically load track comments, without leaving the page. Requires JS |
|
||||
| Player | Player | "restream" if Restream is enabled in backend config, otherwise - "hls" | "restream", "hls", "none" | Method used to play the track in the frontend. HLS - requires JavaScript, loads the track in pieces. Restream - works without JavaScript, loads entire track through the backend right away. None - don't play the track |
|
||||
| Parse descriptions | ParseDescriptions | true | true, false | Turn @mentions, external links (https://example.org) and emails (hello@example.org) inside descriptions into clickable links |
|
||||
| Show current audio | ShowAudio | false | true, false | Show what [audio preset](AUDIO_PRESETS.md) is being streamed below the audio player |
|
||||
| Proxy images | ProxyImages | same as ProxyImages in backend config | true, false | Proxy images through the backend. ProxyImages must be enabled on the backend |
|
||||
| Download audio | DownloadAudio | "mpeg" | "mpeg", "opus", "aac", "best" | What [audio preset](AUDIO_PRESETS.md) should be loaded when downloading audio with metadata. Restream must be enabled on the backend |
|
||||
| Autoplay next track in playlists | AutoplayNextTrack | false | true, false | Automatically start playlist playback when you open a track from the playlist. Requires JS |
|
||||
| Default autoplay mode (in playlists) | DefaultAutoplayMode | "normal" | "normal", "random" | Default mode for playlist autoplay. Normal - play songs in order. Random - play random song next |
|
||||
| Autoplay next related track | AutoplayNextRelatedTrack | false | true, false | Automatically play a related track next. Requires JS
|
||||
| Fetch search suggestions | SearchSuggestions | false | true, false | Load search suggestions on main page when you type. Requires JS |
|
||||
| Dynamically load comments | DynamicLoadComments | false | true, false | Dynamically load track comments, without leaving the page. Requires JS |
|
||||
| Player | Player | "restream" if Restream is enabled in backend config, otherwise - "hls" | "restream", "hls", "none" | Method used to play the track in the frontend. HLS - requires JavaScript, loads the track in pieces. Restream - works without JavaScript, loads entire track through the backend right away. None - don't play the track |
|
||||
|
||||
## Player-specific preferences
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ func defaultPreferences() {
|
||||
|
||||
DefaultPreferences.ParseDescriptions = &True
|
||||
DefaultPreferences.AutoplayNextTrack = &False
|
||||
DefaultPreferences.AutoplayNextRelatedTrack = &False
|
||||
|
||||
p2 := AutoplayNormal
|
||||
DefaultPreferences.DefaultAutoplayMode = &p2
|
||||
@@ -188,6 +189,12 @@ func loadDefaultPreferences(loaded Preferences) {
|
||||
DefaultPreferences.AutoplayNextTrack = &False
|
||||
}
|
||||
|
||||
if loaded.AutoplayNextRelatedTrack != nil {
|
||||
DefaultPreferences.AutoplayNextRelatedTrack = loaded.AutoplayNextRelatedTrack
|
||||
} else {
|
||||
DefaultPreferences.AutoplayNextRelatedTrack = &False
|
||||
}
|
||||
|
||||
if loaded.DefaultAutoplayMode != nil {
|
||||
DefaultPreferences.DefaultAutoplayMode = loaded.DefaultAutoplayMode
|
||||
} else {
|
||||
|
||||
@@ -64,6 +64,9 @@ type Preferences struct {
|
||||
// Automatically play next track in playlists
|
||||
AutoplayNextTrack *bool
|
||||
|
||||
// Automatically play next related track
|
||||
AutoplayNextRelatedTrack *bool
|
||||
|
||||
DefaultAutoplayMode *string // "normal" or "random"
|
||||
|
||||
// Check above for more info
|
||||
|
||||
@@ -36,6 +36,10 @@ func Defaults(dst *cfg.Preferences) {
|
||||
dst.AutoplayNextTrack = cfg.DefaultPreferences.AutoplayNextTrack
|
||||
}
|
||||
|
||||
if dst.AutoplayNextRelatedTrack == nil {
|
||||
dst.AutoplayNextRelatedTrack = cfg.DefaultPreferences.AutoplayNextRelatedTrack
|
||||
}
|
||||
|
||||
if dst.DefaultAutoplayMode == nil {
|
||||
dst.DefaultAutoplayMode = cfg.DefaultPreferences.DefaultAutoplayMode
|
||||
}
|
||||
@@ -79,19 +83,20 @@ func Get(c fiber.Ctx) (cfg.Preferences, error) {
|
||||
}
|
||||
|
||||
type PrefsForm struct {
|
||||
ProxyImages string
|
||||
ParseDescriptions string
|
||||
Player string
|
||||
ProxyStreams string
|
||||
FullyPreloadTrack string
|
||||
AutoplayNextTrack string
|
||||
DefaultAutoplayMode string
|
||||
HLSAudio string
|
||||
RestreamAudio string
|
||||
DownloadAudio string
|
||||
ShowAudio string
|
||||
SearchSuggestions string
|
||||
DynamicLoadComments string
|
||||
ProxyImages string
|
||||
ParseDescriptions string
|
||||
Player string
|
||||
ProxyStreams string
|
||||
FullyPreloadTrack string
|
||||
AutoplayNextTrack string
|
||||
AutoplayNextRelatedTrack string
|
||||
DefaultAutoplayMode string
|
||||
HLSAudio string
|
||||
RestreamAudio string
|
||||
DownloadAudio string
|
||||
ShowAudio string
|
||||
SearchSuggestions string
|
||||
DynamicLoadComments string
|
||||
}
|
||||
|
||||
type Export struct {
|
||||
@@ -131,6 +136,12 @@ func Load(r *fiber.App) {
|
||||
old.AutoplayNextTrack = &cfg.False
|
||||
}
|
||||
|
||||
if p.AutoplayNextRelatedTrack == "on" {
|
||||
old.AutoplayNextRelatedTrack = &cfg.True
|
||||
} else {
|
||||
old.AutoplayNextRelatedTrack = &cfg.False
|
||||
}
|
||||
|
||||
if p.ShowAudio == "on" {
|
||||
old.ShowAudio = &cfg.True
|
||||
} else {
|
||||
|
||||
67
main.go
67
main.go
@@ -52,8 +52,7 @@ func (osfs) Open(name string) (fs.File, error) {
|
||||
return f, err
|
||||
}
|
||||
|
||||
type staticfs struct {
|
||||
}
|
||||
type staticfs struct{}
|
||||
|
||||
func (staticfs) Open(name string) (fs.File, error) {
|
||||
misc.Log("staticfs:", name)
|
||||
@@ -150,7 +149,7 @@ func main() {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("", templates.MainPage(prefs), templates.MainPageHead()).Render(c.RequestCtx(), c)
|
||||
}
|
||||
|
||||
@@ -158,7 +157,6 @@ func main() {
|
||||
app.Get("/index.html", mainPageHandler)
|
||||
}
|
||||
|
||||
const AssetsCacheControl = "public, max-age=28800" // 8hrs
|
||||
if cfg.EmbedFiles {
|
||||
misc.Log("using embedded files")
|
||||
ServeFromFS(app, staticfs{})
|
||||
@@ -171,7 +169,7 @@ func main() {
|
||||
// try to load favicon from default location,
|
||||
// and this path loads the user "favicon" by default
|
||||
app.Get("favicon.ico", func(c fiber.Ctx) error {
|
||||
return c.Redirect().To("/_/static/favicon.ico")
|
||||
return c.Redirect().Status(fiber.StatusPermanentRedirect).To("/_/static/favicon.ico")
|
||||
})
|
||||
|
||||
app.Get("robots.txt", func(c fiber.Ctx) error {
|
||||
@@ -195,7 +193,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("tracks: "+q, templates.SearchTracks(p), nil).Render(c.RequestCtx(), c)
|
||||
|
||||
case "users":
|
||||
@@ -205,7 +203,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("users: "+q, templates.SearchUsers(p), nil).Render(c.RequestCtx(), c)
|
||||
|
||||
case "playlists":
|
||||
@@ -215,7 +213,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("playlists: "+q, templates.SearchPlaylists(p), nil).Render(c.RequestCtx(), c)
|
||||
}
|
||||
|
||||
@@ -310,7 +308,7 @@ Disallow: /`)
|
||||
}
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.TrackEmbed(prefs, track, stream, displayErr).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -332,7 +330,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("Recent tracks tagged "+tag, templates.RecentTracks(tag, p), nil).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -354,7 +352,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("Popular tracks tagged "+tag, templates.PopularTracks(tag, p), nil).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -377,7 +375,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("Playlists tagged "+tag, templates.TaggedPlaylists(tag, p), nil).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -393,7 +391,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("Featured Tracks", templates.FeaturedTracks(tracks), nil).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -409,7 +407,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base("Discover", templates.Discover(selections), nil).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -446,7 +444,7 @@ Disallow: /`)
|
||||
}
|
||||
|
||||
app.Get("/_/info", func(c fiber.Ctx) error {
|
||||
c.Set("Content-Type", "application/json")
|
||||
c.Response().Header.SetContentType("application/json")
|
||||
return c.Send(inf)
|
||||
})
|
||||
}
|
||||
@@ -500,7 +498,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserPlaylists(prefs, user, pl), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -528,7 +526,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserAlbums(prefs, user, pl), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -556,7 +554,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserReposts(prefs, user, p), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -584,7 +582,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserLikes(prefs, user, p), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -612,7 +610,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserTopTracks(prefs, user, p), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -640,7 +638,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserFollowers(prefs, user, p), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -668,7 +666,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserFollowing(prefs, user, p), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -762,6 +760,17 @@ Disallow: /`)
|
||||
}
|
||||
}
|
||||
|
||||
if *prefs.AutoplayNextRelatedTrack && nextTrack == nil && string(c.RequestCtx().QueryArgs().Peek("playRelated")) != "false" {
|
||||
rel, err := track.GetRelated(cid, prefs, "?limit=4")
|
||||
if err == nil && len(rel.Collection) != 0 {
|
||||
prev := c.RequestCtx().QueryArgs().Peek("prev")
|
||||
nextTrack = &track
|
||||
for i := len(rel.Collection) - 1; i >= 0 && (string(nextTrack.ID) == string(track.ID) || string(nextTrack.ID) == string(prev)); i-- {
|
||||
nextTrack = rel.Collection[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var comments *sc.Paginated[*sc.Comment]
|
||||
if q := c.Query("pagination"); q != "" {
|
||||
comments, err = track.GetComments(cid, prefs, q)
|
||||
@@ -777,7 +786,7 @@ Disallow: /`)
|
||||
downloadAudio = &audio
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(track.Title+" by "+track.Author.Username, templates.Track(prefs, track, stream, displayErr, string(c.RequestCtx().QueryArgs().Peek("autoplay")) == "true", playlist, nextTrack, c.Query("volume"), mode, audio, downloadAudio, comments), templates.TrackHeader(prefs, track, true)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -836,7 +845,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(usr.Username, templates.User(prefs, usr, p), templates.UserHeader(usr)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -876,7 +885,7 @@ Disallow: /`)
|
||||
playlist.MissingTracks = strings.Join(next, ",")
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(playlist.Title+" by "+playlist.Author.Username, templates.Playlist(prefs, playlist), templates.PlaylistHeader(playlist)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -904,7 +913,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(user.Username, templates.UserRelated(prefs, user, r), templates.UserHeader(user)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -933,7 +942,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(track.Title+" by "+track.Author.Username, templates.RelatedTracks(track, r), templates.TrackHeader(prefs, track, false)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -961,7 +970,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInPlaylists(track, p), templates.TrackHeader(prefs, track, false)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
@@ -989,7 +998,7 @@ Disallow: /`)
|
||||
return err
|
||||
}
|
||||
|
||||
c.Set("Content-Type", "text/html")
|
||||
c.Response().Header.SetContentType("text/html")
|
||||
return templates.Base(track.Title+" by "+track.Author.Username, templates.TrackInAlbums(track, p), templates.TrackHeader(prefs, track, false)).Render(c.RequestCtx(), c)
|
||||
})
|
||||
|
||||
|
||||
@@ -69,13 +69,18 @@ templ Preferences(prefs cfg.Preferences) {
|
||||
</label>
|
||||
if *prefs.AutoplayNextTrack {
|
||||
<label>
|
||||
Default autoplay mode:
|
||||
Default autoplay mode (in playlists):
|
||||
@sel("DefaultAutoplayMode", []option{
|
||||
{"normal", "Normal (play songs in order)", false},
|
||||
{"random", "Random (play random song)", false},
|
||||
}, *prefs.DefaultAutoplayMode)
|
||||
</label>
|
||||
}
|
||||
<label>
|
||||
Autoplay next related track:
|
||||
@checkbox("AutoplayNextRelatedTrack", *prefs.AutoplayNextRelatedTrack)
|
||||
(requires JS; you need to allow autoplay from this domain!!)
|
||||
</label>
|
||||
<label>
|
||||
Fetch search suggestions:
|
||||
@checkbox("SearchSuggestions", *prefs.SearchSuggestions)
|
||||
|
||||
@@ -52,17 +52,33 @@ templ TrackHeader(prefs cfg.Preferences, t sc.Track, needPlayer bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func next(t *sc.Track, p *sc.Playlist, autoplay bool, mode string, volume string) string {
|
||||
r := t.Href() + "?playlist=" + p.Href()[1:]
|
||||
if autoplay {
|
||||
r += "&autoplay=true"
|
||||
func next(c *sc.Track, t *sc.Track, p *sc.Playlist, autoplay bool, mode string, volume string) string {
|
||||
r := t.Href()
|
||||
|
||||
if p != nil {
|
||||
r += "?playlist=" + p.Href()[1:]
|
||||
}
|
||||
|
||||
if autoplay {
|
||||
if p == nil {
|
||||
r += "?"
|
||||
} else {
|
||||
r += "&"
|
||||
}
|
||||
r += "autoplay=true"
|
||||
}
|
||||
|
||||
if mode != "" {
|
||||
r += "&mode=" + mode
|
||||
}
|
||||
|
||||
if volume != "" {
|
||||
r += "&volume=" + volume
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
r += "&prev=" + string(c.ID)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -75,7 +91,7 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
if cfg.Restream && *prefs.Player == cfg.RestreamPlayer {
|
||||
{{ audioPref = *prefs.RestreamAudio }}
|
||||
if nextTrack != nil {
|
||||
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay } data-next={ next(nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
<script async src="/_/static/restream.js"></script>
|
||||
} else {
|
||||
<audio src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
|
||||
@@ -83,7 +99,7 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
} else if stream != "" {
|
||||
{{ audioPref = *prefs.HLSAudio }}
|
||||
if nextTrack != nil {
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={ next(nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
} else {
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay }></audio>
|
||||
}
|
||||
@@ -159,20 +175,28 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
|
||||
if t.Genre != "" {
|
||||
<a href={ templ.SafeURL("/tags/" + t.Genre) }><p class="tag">{ t.Genre }</p></a>
|
||||
}
|
||||
if playlist != nil {
|
||||
if nextTrack != nil {
|
||||
<details open style="margin-bottom: 1rem;">
|
||||
<summary>Playback info</summary>
|
||||
<h2>In playlist:</h2>
|
||||
@PlaylistItem(playlist, true)
|
||||
|
||||
if playlist != nil {
|
||||
<h2>In playlist:</h2>
|
||||
@PlaylistItem(playlist, true)
|
||||
}
|
||||
|
||||
<h2>Next track:</h2>
|
||||
@TrackItem(nextTrack, true, next(nextTrack, playlist, true, mode, volume))
|
||||
@TrackItem(nextTrack, true, next(&t, nextTrack, playlist, true, mode, volume))
|
||||
<div style="display: flex; gap: 1rem">
|
||||
if playlist != nil {
|
||||
<a href={ templ.SafeURL(t.Href()) } class="btn">Stop playlist playback</a>
|
||||
if mode != cfg.AutoplayRandom {
|
||||
<a href={ templ.SafeURL(next(&t, playlist, false, cfg.AutoplayRandom, volume)) } class="btn">Switch to random mode</a>
|
||||
<a href={ templ.SafeURL(next(nil, &t, playlist, false, cfg.AutoplayRandom, volume)) } class="btn">Switch to random mode</a>
|
||||
} else {
|
||||
<a href={ templ.SafeURL(next(&t, playlist, false, cfg.AutoplayNormal, volume)) } class="btn">Switch to normal mode</a>
|
||||
<a href={ templ.SafeURL(next(nil, &t, playlist, false, cfg.AutoplayNormal, volume)) } class="btn">Switch to normal mode</a>
|
||||
}
|
||||
} else {
|
||||
<a href={ templ.SafeURL(t.Href() + "?playRelated=false") } class="btn">Stop playback</a>
|
||||
}
|
||||
</div>
|
||||
</details>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user