mirror of
https://git.maid.zone/stuff/soundcloak.git
synced 2025-12-10 05:39:38 +05:00
KeepPlayerFocus pref, rework prefs page, always autoplay if you click on the next track
This commit is contained in:
@@ -1,22 +1,16 @@
|
||||
# Preferences
|
||||
|
||||
|
||||
| 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 (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 preferences
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :--------------------------------- | --------------------- | ------------------------------------------------------------------------ | ------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 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
|
||||
|
||||
### HLS Player
|
||||
## HLS Player
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :-------------------- | ------------------- | ---------------------------------------- | ----------------- | :------------------------------------------------------------------------------------ |
|
||||
@@ -24,9 +18,30 @@
|
||||
| Fully preload track | FullyPreloadTrack | false | true, false | Fully load track when the page is loaded (track stream expires in ~5 minutes) |
|
||||
| Streaming audio | HLSAudio | "mpeg" | "mpeg", "aac" | What [audio preset](AUDIO_PRESETS.md) should be loaded when streaming audio |
|
||||
|
||||
### Restream Player
|
||||
## Restream Player
|
||||
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :---------------- | --------------- | --------- | ------------------------------- | :--------------------------------------------------------------------------- |
|
||||
| Streaming audio | RestreamAudio | "mpeg" | "mpeg", "opus", "aac", "best" | What [audio preset](AUDIO_PRESETS.md) should be loaded when streaming audio |
|
||||
|
||||
|
||||
# Frontend enhancements
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :--------------------------------- | --------------------- | ------------------------------------------------------------------------ | ------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Proxy images | ProxyImages | same as ProxyImages in backend config | true, false | Proxy images through the backend. ProxyImages must be enabled on the backend |
|
||||
| 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 |
|
||||
| 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
|
||||
| Keep player focus | KeepPlayerFocus | false | true, false | Always keep track element in focus, so you can control it with keyboard. Requires JS |
|
||||
|
||||
## Autoplay
|
||||
*Requires JS. You also need to allow autoplay from this domain*
|
||||
|
||||
| Name | Key | Default | Possible values | Description |
|
||||
| :--------------------------------- | --------------------- | ------------------------------------------------------------------------ | ------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Autoplay next track in playlists | AutoplayNextTrack | false | true, false | Automatically start playlist playback when you open a track from the playlist. |
|
||||
| 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.
|
||||
@@ -1,7 +1,6 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -144,6 +143,7 @@ func defaultPreferences() {
|
||||
|
||||
DefaultPreferences.SearchSuggestions = &False
|
||||
DefaultPreferences.DynamicLoadComments = &False
|
||||
DefaultPreferences.KeepPlayerFocus = &False
|
||||
}
|
||||
|
||||
func loadDefaultPreferences(loaded Preferences) {
|
||||
@@ -238,21 +238,18 @@ func loadDefaultPreferences(loaded Preferences) {
|
||||
} else {
|
||||
DefaultPreferences.DynamicLoadComments = &False
|
||||
}
|
||||
|
||||
if loaded.KeepPlayerFocus != nil {
|
||||
DefaultPreferences.KeepPlayerFocus = loaded.KeepPlayerFocus
|
||||
} else {
|
||||
DefaultPreferences.KeepPlayerFocus = &False
|
||||
}
|
||||
}
|
||||
|
||||
func boolean(in string) bool {
|
||||
return strings.Trim(strings.ToLower(in), " ") == "true"
|
||||
}
|
||||
|
||||
type wrappedError struct {
|
||||
err error
|
||||
fault string
|
||||
}
|
||||
|
||||
func (w wrappedError) Error() string {
|
||||
return fmt.Sprintf("error loading %s: %s", w.fault, w.err)
|
||||
}
|
||||
|
||||
func fromEnv() error {
|
||||
env := os.Getenv("GET_WEB_PROFILES")
|
||||
if env != "" {
|
||||
@@ -264,7 +261,7 @@ func fromEnv() error {
|
||||
var p Preferences
|
||||
err := json.Unmarshal(S2b(env), &p)
|
||||
if err != nil {
|
||||
return wrappedError{err, "DEFAULT_PREFERENCES"}
|
||||
return err
|
||||
}
|
||||
|
||||
loadDefaultPreferences(p)
|
||||
@@ -306,7 +303,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "CLIENT_ID_TTL"}
|
||||
return err
|
||||
}
|
||||
|
||||
ClientIDTTL = time.Duration(num) * time.Second
|
||||
@@ -316,7 +313,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "USER_TTL"}
|
||||
return err
|
||||
}
|
||||
|
||||
UserTTL = time.Duration(num) * time.Second
|
||||
@@ -326,7 +323,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "USER_CACHE_CLEAN_DELAY"}
|
||||
return err
|
||||
}
|
||||
|
||||
UserCacheCleanDelay = time.Duration(num) * time.Second
|
||||
@@ -336,7 +333,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "TRACK_TTL"}
|
||||
return err
|
||||
}
|
||||
|
||||
TrackTTL = time.Duration(num) * time.Second
|
||||
@@ -346,7 +343,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "TRACK_CACHE_CLEAN_DELAY"}
|
||||
return err
|
||||
}
|
||||
|
||||
TrackCacheCleanDelay = time.Duration(num) * time.Second
|
||||
@@ -356,7 +353,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "PLAYLIST_TTL"}
|
||||
return err
|
||||
}
|
||||
|
||||
PlaylistTTL = time.Duration(num) * time.Second
|
||||
@@ -366,7 +363,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "PLAYLIST_CACHE_CLEAN_DELAY"}
|
||||
return err
|
||||
}
|
||||
|
||||
PlaylistCacheCleanDelay = time.Duration(num) * time.Second
|
||||
@@ -381,7 +378,7 @@ func fromEnv() error {
|
||||
if env != "" {
|
||||
num, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return wrappedError{err, "DNS_CACHE_TTL"}
|
||||
return err
|
||||
}
|
||||
|
||||
DNSCacheTTL = time.Duration(num) * time.Second
|
||||
@@ -412,7 +409,7 @@ func fromEnv() error {
|
||||
var p []string
|
||||
err := json.Unmarshal(S2b(env), &p)
|
||||
if err != nil {
|
||||
return wrappedError{err, "TRUSTED_PROXIES"}
|
||||
return err
|
||||
}
|
||||
|
||||
TrustedProxies = p
|
||||
@@ -436,12 +433,8 @@ func init() {
|
||||
if env := os.Getenv("SOUNDCLOAK_CONFIG"); env == "FROM_ENV" {
|
||||
err := fromEnv()
|
||||
if err != nil {
|
||||
// So we only set default preferences if it fails to load that in
|
||||
if err.(wrappedError).fault == "DEFAULT_PREFERENCES" {
|
||||
defaultPreferences()
|
||||
}
|
||||
|
||||
log.Println("failed to load config from environment:", err)
|
||||
log.Println("Warning: failed to load config from environment:", err)
|
||||
defaultPreferences()
|
||||
}
|
||||
|
||||
return
|
||||
@@ -451,7 +444,7 @@ func init() {
|
||||
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
log.Printf("failed to load config from %s: %s\n", filename, err)
|
||||
log.Printf("Warning: failed to load config from %s: %s\n", filename, err)
|
||||
defaultPreferences()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -80,6 +80,8 @@ type Preferences struct {
|
||||
SearchSuggestions *bool // load search suggestions on main page
|
||||
|
||||
DynamicLoadComments *bool // dynamic comments loader without leaving track page
|
||||
|
||||
KeepPlayerFocus *bool // keep player element in focus
|
||||
}
|
||||
|
||||
func B2s(b []byte) string {
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
const on = "on"
|
||||
|
||||
func Defaults(dst *cfg.Preferences) {
|
||||
if dst.Player == nil {
|
||||
dst.Player = cfg.DefaultPreferences.Player
|
||||
@@ -67,6 +69,10 @@ func Defaults(dst *cfg.Preferences) {
|
||||
if dst.DynamicLoadComments == nil {
|
||||
dst.DynamicLoadComments = cfg.DefaultPreferences.DynamicLoadComments
|
||||
}
|
||||
|
||||
if dst.KeepPlayerFocus == nil {
|
||||
dst.KeepPlayerFocus = cfg.DefaultPreferences.KeepPlayerFocus
|
||||
}
|
||||
}
|
||||
|
||||
func Get(c fiber.Ctx) (cfg.Preferences, error) {
|
||||
@@ -97,6 +103,7 @@ type PrefsForm struct {
|
||||
ShowAudio string
|
||||
SearchSuggestions string
|
||||
DynamicLoadComments string
|
||||
KeepPlayerFocus string
|
||||
}
|
||||
|
||||
type Export struct {
|
||||
@@ -130,19 +137,19 @@ func Load(r *fiber.App) {
|
||||
old.DefaultAutoplayMode = &p.DefaultAutoplayMode
|
||||
}
|
||||
|
||||
if p.AutoplayNextTrack == "on" {
|
||||
if p.AutoplayNextTrack == on {
|
||||
old.AutoplayNextTrack = &cfg.True
|
||||
} else {
|
||||
old.AutoplayNextTrack = &cfg.False
|
||||
}
|
||||
|
||||
if p.AutoplayNextRelatedTrack == "on" {
|
||||
if p.AutoplayNextRelatedTrack == on {
|
||||
old.AutoplayNextRelatedTrack = &cfg.True
|
||||
} else {
|
||||
old.AutoplayNextRelatedTrack = &cfg.False
|
||||
}
|
||||
|
||||
if p.ShowAudio == "on" {
|
||||
if p.ShowAudio == on {
|
||||
old.ShowAudio = &cfg.True
|
||||
} else {
|
||||
old.ShowAudio = &cfg.False
|
||||
@@ -150,14 +157,14 @@ func Load(r *fiber.App) {
|
||||
|
||||
if *old.Player == cfg.HLSPlayer {
|
||||
if cfg.ProxyStreams {
|
||||
if p.ProxyStreams == "on" {
|
||||
if p.ProxyStreams == on {
|
||||
old.ProxyStreams = &cfg.True
|
||||
} else if p.ProxyStreams == "" {
|
||||
old.ProxyStreams = &cfg.False
|
||||
}
|
||||
}
|
||||
|
||||
if p.FullyPreloadTrack == "on" {
|
||||
if p.FullyPreloadTrack == on {
|
||||
old.FullyPreloadTrack = &cfg.True
|
||||
} else if p.FullyPreloadTrack == "" {
|
||||
old.FullyPreloadTrack = &cfg.False
|
||||
@@ -175,31 +182,37 @@ func Load(r *fiber.App) {
|
||||
}
|
||||
|
||||
if cfg.ProxyImages {
|
||||
if p.ProxyImages == "on" {
|
||||
if p.ProxyImages == on {
|
||||
old.ProxyImages = &cfg.True
|
||||
} else if p.ProxyImages == "" {
|
||||
old.ProxyImages = &cfg.False
|
||||
}
|
||||
}
|
||||
|
||||
if p.ParseDescriptions == "on" {
|
||||
if p.ParseDescriptions == on {
|
||||
old.ParseDescriptions = &cfg.True
|
||||
} else {
|
||||
old.ParseDescriptions = &cfg.False
|
||||
}
|
||||
|
||||
if p.SearchSuggestions == "on" {
|
||||
if p.SearchSuggestions == on {
|
||||
old.SearchSuggestions = &cfg.True
|
||||
} else {
|
||||
old.SearchSuggestions = &cfg.False
|
||||
}
|
||||
|
||||
if p.DynamicLoadComments == "on" {
|
||||
if p.DynamicLoadComments == on {
|
||||
old.DynamicLoadComments = &cfg.True
|
||||
} else {
|
||||
old.DynamicLoadComments = &cfg.False
|
||||
}
|
||||
|
||||
if p.KeepPlayerFocus == on {
|
||||
old.KeepPlayerFocus = &cfg.True
|
||||
} else {
|
||||
old.KeepPlayerFocus = &cfg.False
|
||||
}
|
||||
|
||||
old.Player = &p.Player
|
||||
|
||||
data, err := json.Marshal(old)
|
||||
|
||||
9
static/assets/keepfocus.js
Normal file
9
static/assets/keepfocus.js
Normal file
@@ -0,0 +1,9 @@
|
||||
var audio = document.getElementById('track');
|
||||
audio.onblur = function (e) {
|
||||
if (e.target != e.relatedTarget) {
|
||||
setTimeout(function() {
|
||||
e.target.focus({preventScroll: true, focusVisible: false});
|
||||
})
|
||||
}
|
||||
}
|
||||
audio.focus({focusVisible: false});
|
||||
@@ -42,55 +42,13 @@ templ sel_audio(name string, selected string, noOpus bool) {
|
||||
templ Preferences(prefs cfg.Preferences) {
|
||||
<h1>Preferences</h1>
|
||||
<form method="post" autocomplete="off">
|
||||
<label>
|
||||
Parse descriptions:
|
||||
@checkbox("ParseDescriptions", *prefs.ParseDescriptions)
|
||||
</label>
|
||||
<label>
|
||||
Show current audio:
|
||||
@checkbox("ShowAudio", *prefs.ShowAudio)
|
||||
</label>
|
||||
if cfg.ProxyImages {
|
||||
<label>
|
||||
Proxy images:
|
||||
@checkbox("ProxyImages", *prefs.ProxyImages)
|
||||
</label>
|
||||
}
|
||||
if cfg.Restream {
|
||||
<label>
|
||||
Download audio:
|
||||
@sel_audio("DownloadAudio", *prefs.DownloadAudio, false)
|
||||
</label>
|
||||
}
|
||||
<label>
|
||||
Autoplay next track in playlists:
|
||||
@checkbox("AutoplayNextTrack", *prefs.AutoplayNextTrack)
|
||||
(requires JS; you need to allow autoplay from this domain!!)
|
||||
</label>
|
||||
if *prefs.AutoplayNextTrack {
|
||||
<label>
|
||||
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)
|
||||
(requires JS)
|
||||
</label>
|
||||
<label>
|
||||
Dynamically load comments:
|
||||
@checkbox("DynamicLoadComments", *prefs.DynamicLoadComments)
|
||||
(requires JS)
|
||||
</label>
|
||||
<h1>Player preferences</h1>
|
||||
<label>
|
||||
Player:
|
||||
@sel("Player", []option{
|
||||
@@ -101,7 +59,6 @@ templ Preferences(prefs cfg.Preferences) {
|
||||
</label>
|
||||
switch *prefs.Player {
|
||||
case cfg.HLSPlayer:
|
||||
<h1>Player-specific preferences</h1>
|
||||
if cfg.ProxyStreams {
|
||||
<label>
|
||||
Proxy song streams:
|
||||
@@ -117,12 +74,60 @@ templ Preferences(prefs cfg.Preferences) {
|
||||
@sel_audio("HLSAudio", *prefs.HLSAudio, true)
|
||||
</label>
|
||||
case cfg.RestreamPlayer:
|
||||
<h1>Player-specific preferences</h1>
|
||||
<label>
|
||||
Streaming audio:
|
||||
@sel_audio("RestreamAudio", *prefs.RestreamAudio, false)
|
||||
</label>
|
||||
}
|
||||
<h1>Frontend enhancements</h1>
|
||||
if cfg.ProxyImages {
|
||||
<label>
|
||||
Proxy images:
|
||||
@checkbox("ProxyImages", *prefs.ProxyImages)
|
||||
</label>
|
||||
}
|
||||
<label>
|
||||
Parse descriptions:
|
||||
@checkbox("ParseDescriptions", *prefs.ParseDescriptions)
|
||||
</label>
|
||||
<label>
|
||||
Show current audio:
|
||||
@checkbox("ShowAudio", *prefs.ShowAudio)
|
||||
</label>
|
||||
<label>
|
||||
Fetch search suggestions:
|
||||
@checkbox("SearchSuggestions", *prefs.SearchSuggestions)
|
||||
(requires JS)
|
||||
</label>
|
||||
<label>
|
||||
Dynamically load comments:
|
||||
@checkbox("DynamicLoadComments", *prefs.DynamicLoadComments)
|
||||
(requires JS)
|
||||
</label>
|
||||
<label>
|
||||
Keep player focus:
|
||||
@checkbox("KeepPlayerFocus", *prefs.KeepPlayerFocus)
|
||||
(requires JS)
|
||||
</label>
|
||||
<h2 style="margin-bottom: .35rem">Autoplay</h2>
|
||||
<i>Requires JS. You also need to allow autoplay from this domain</i>
|
||||
<label style="margin-top: 1rem">
|
||||
Autoplay next track in playlists:
|
||||
@checkbox("AutoplayNextTrack", *prefs.AutoplayNextTrack)
|
||||
</label>
|
||||
if *prefs.AutoplayNextTrack {
|
||||
<label>
|
||||
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)
|
||||
</label>
|
||||
<input type="submit" value="Update" class="btn" style="margin-top: 1rem;"/>
|
||||
<p>These preferences get saved in a cookie.</p>
|
||||
</form>
|
||||
@@ -137,6 +142,5 @@ templ Preferences(prefs cfg.Preferences) {
|
||||
<input class="btn" type="file" autocomplete="off" name="prefs"/>
|
||||
<input type="submit" value="Import" class="btn"/>
|
||||
</form>
|
||||
|
||||
<style>label{display:flex;gap:.5rem;align-items:center;margin-bottom:.35rem}</style>
|
||||
}
|
||||
|
||||
@@ -47,38 +47,36 @@ templ TrackHeader(prefs cfg.Preferences, t sc.Track, needPlayer bool) {
|
||||
<meta name="og:description" content={ t.FormatDescription() }/>
|
||||
<meta name="og:image" content={ t.Artwork }/>
|
||||
<link rel="icon" type="image/x-icon" href={ t.Artwork }/>
|
||||
if needPlayer && *prefs.Player == cfg.HLSPlayer {
|
||||
<script src="/_/static/js/hls.light.min.js"></script>
|
||||
if needPlayer {
|
||||
if *prefs.Player == cfg.HLSPlayer {
|
||||
<script src="/_/static/js/hls.light.min.js"></script>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func next(c *sc.Track, t *sc.Track, p *sc.Playlist, autoplay bool, mode string, volume string) string {
|
||||
func next(c *sc.Track, t *sc.Track, p *sc.Playlist, mode string, volume string) string {
|
||||
r := t.Href()
|
||||
|
||||
if p != nil {
|
||||
r += "?playlist=" + p.Href()[1:]
|
||||
}
|
||||
|
||||
if autoplay {
|
||||
if p == nil {
|
||||
r += "?"
|
||||
} else {
|
||||
r += "&"
|
||||
if mode != "" {
|
||||
r += "&mode=" + mode
|
||||
}
|
||||
r += "&"
|
||||
} else {
|
||||
r += "?"
|
||||
|
||||
if c != nil {
|
||||
r += "prev=" + string(c.ID) + "&"
|
||||
}
|
||||
r += "autoplay=true"
|
||||
}
|
||||
|
||||
if mode != "" {
|
||||
r += "&mode=" + mode
|
||||
}
|
||||
r += "autoplay=true"
|
||||
|
||||
if volume != "" {
|
||||
r += "&volume=" + volume
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
r += "&prev=" + string(c.ID)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -87,19 +85,22 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
{{ return }}
|
||||
}
|
||||
if displayErr == "" {
|
||||
{{ var audioPref string }}
|
||||
{{ var audioPref *string }}
|
||||
if cfg.Restream && *prefs.Player == cfg.RestreamPlayer {
|
||||
{{ audioPref = *prefs.RestreamAudio }}
|
||||
{{ audioPref = prefs.RestreamAudio }}
|
||||
if nextTrack != nil {
|
||||
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, mode, "") } volume={ volume }></audio>
|
||||
<script async src="/_/static/restream.js"></script>
|
||||
} else {
|
||||
<audio src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
|
||||
<audio id="track" src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
|
||||
}
|
||||
if *prefs.KeepPlayerFocus {
|
||||
<script async src="/_/static/keepfocus.js"></script>
|
||||
}
|
||||
} else if stream != "" {
|
||||
{{ audioPref = *prefs.HLSAudio }}
|
||||
{{ audioPref = prefs.HLSAudio }}
|
||||
if nextTrack != nil {
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, true, mode, "") } volume={ volume }></audio>
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={ next(&track, nextTrack, playlist, mode, "") } volume={ volume }></audio>
|
||||
} else {
|
||||
<audio id="track" src={ stream } controls autoplay?={ autoplay }></audio>
|
||||
}
|
||||
@@ -108,6 +109,9 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
} else {
|
||||
<script async src="/_/static/player.js"></script>
|
||||
}
|
||||
if *prefs.KeepPlayerFocus {
|
||||
<script async src="/_/static/keepfocus.js"></script>
|
||||
}
|
||||
<noscript>
|
||||
<br/>
|
||||
JavaScript is disabled! Audio playback may not work without it enabled.
|
||||
@@ -124,7 +128,7 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
||||
}
|
||||
if *prefs.ShowAudio {
|
||||
<div>
|
||||
if audioPref == cfg.AudioBest {
|
||||
if *audioPref == cfg.AudioBest {
|
||||
<p>Audio: best ({ audio })</p>
|
||||
} else {
|
||||
<p>Audio: { audio }</p>
|
||||
@@ -178,25 +182,23 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
|
||||
if nextTrack != nil {
|
||||
<details open style="margin-bottom: 1rem;">
|
||||
<summary>Playback info</summary>
|
||||
|
||||
if playlist != nil {
|
||||
<h2>In playlist:</h2>
|
||||
@PlaylistItem(playlist, true)
|
||||
}
|
||||
|
||||
<h2>Next track:</h2>
|
||||
@TrackItem(nextTrack, true, next(&t, nextTrack, playlist, true, mode, volume))
|
||||
@TrackItem(nextTrack, true, next(&t, nextTrack, playlist, 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(nil, &t, playlist, false, cfg.AutoplayRandom, volume)) } class="btn">Switch to random mode</a>
|
||||
if playlist != nil {
|
||||
<a href={ templ.SafeURL(t.Href()) } class="btn">Stop playlist playback</a>
|
||||
if mode != cfg.AutoplayRandom {
|
||||
<a href={ templ.SafeURL(next(nil, &t, playlist, cfg.AutoplayRandom, volume)) } class="btn">Switch to random mode</a>
|
||||
} else {
|
||||
<a href={ templ.SafeURL(next(nil, &t, playlist, cfg.AutoplayNormal, volume)) } class="btn">Switch to normal mode</a>
|
||||
}
|
||||
} else {
|
||||
<a href={ templ.SafeURL(next(nil, &t, playlist, false, cfg.AutoplayNormal, volume)) } class="btn">Switch to normal mode</a>
|
||||
<a href={ templ.SafeURL(t.Href() + "?playRelated=false") } class="btn">Stop playback</a>
|
||||
}
|
||||
} else {
|
||||
<a href={ templ.SafeURL(t.Href() + "?playRelated=false") } class="btn">Stop playback</a>
|
||||
}
|
||||
</div>
|
||||
</details>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user