mirror of
https://git.maid.zone/stuff/soundcloak.git
synced 2025-12-10 13:49:39 +05:00
Shuffle mode for autoplay; fix proxying with autoplay
This commit is contained in:
48
README.md
48
README.md
@@ -38,7 +38,7 @@ Available features:
|
|||||||
- - Proxy streams: Retrieve song pieces through the instance, instead of going to soundcloud's servers for them
|
- - Proxy streams: Retrieve song pieces through the instance, instead of going to soundcloud's servers for them
|
||||||
- - Fully preload track: Fully loads the track when you load the page instead of buffering a small part of it
|
- - Fully preload track: Fully loads the track when you load the page instead of buffering a small part of it
|
||||||
- - Autoplay next track in playlists: self-explanatory
|
- - Autoplay next track in playlists: self-explanatory
|
||||||
|
- - Default autoplay mode: Default mode for autoplaying. Can be normal (play songs in order) or random (play random song)
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Contributions are appreciated! This includes feedback, feature requests, issues, pull requests and etc.
|
Contributions are appreciated! This includes feedback, feature requests, issues, pull requests and etc.
|
||||||
@@ -189,29 +189,29 @@ Some notes:
|
|||||||
- When specifying time, specify it in seconds.
|
- When specifying time, specify it in seconds.
|
||||||
|
|
||||||
|
|
||||||
| JSON key | Environment variable | Default value | Description |
|
| 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. |
|
| 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) |
|
| 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, "AutoplayNextTrack": false} | 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) |
|
| DefaultPreferences | DEFAULT_PREFERENCES | {"Player": "hls", "ProxyStreams": false, "FullyPreloadTrack": false, "ProxyImages": false, "ParseDescriptions": true, "AutoplayNextTrack": false, "DefaultAutoplayMode": "normal"} | 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) |
|
| 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. |
|
| 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. |
|
||||||
| ProxyStreams | PROXY_STREAMS | false | Enables proxying of song parts and hls playlist files |
|
| ProxyStreams | PROXY_STREAMS | false | Enables proxying of song parts and hls playlist files |
|
||||||
| Restream | RESTREAM | false | Enables Restream Player in settings and the /_/restream/:author/:track endpoint. This player can be used without JavaScript. Restream also enables the button for downloading songs. |
|
| Restream | RESTREAM | false | Enables Restream Player in settings and the /_/restream/:author/:track endpoint. This player can be used without JavaScript. Restream also enables the button for downloading songs. |
|
||||||
| RestreamCacheControl | RESTREAM_CACHE_CONTROL | max-age=3600, public, immutable | [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) header value for restreamed songs. Cached for 1 hour by default. |
|
| RestreamCacheControl | RESTREAM_CACHE_CONTROL | max-age=3600, public, immutable | [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) header value for restreamed songs. Cached for 1 hour by default. |
|
||||||
| ClientIDTTL | CLIENT_ID_TTL | 4 hours | Time until ClientID cache expires. ClientID is used for authenticating with SoundCloud API |
|
| ClientIDTTL | CLIENT_ID_TTL | 4 hours | Time until ClientID cache expires. ClientID is used for authenticating with SoundCloud API |
|
||||||
| UserTTL | USER_TTL | 20 minutes | Time until User profile cache expires |
|
| UserTTL | USER_TTL | 20 minutes | Time until User profile cache expires |
|
||||||
| UserCacheCleanDelay | USER_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired users) |
|
| UserCacheCleanDelay | USER_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired users) |
|
||||||
| TrackTTL | TRACK_TTL | 20 minutes | Time until Track data cache expires |
|
| TrackTTL | TRACK_TTL | 20 minutes | Time until Track data cache expires |
|
||||||
| TrackCacheCleanDelay | TRACK_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired tracks) |
|
| TrackCacheCleanDelay | TRACK_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired tracks) |
|
||||||
| PlaylistTTL | PLAYLIST_TTL | 20 minutes | Time until Playlist data cache expires |
|
| PlaylistTTL | PLAYLIST_TTL | 20 minutes | Time until Playlist data cache expires |
|
||||||
| PlaylistCacheCleanDelay | PLAYLIST_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired playlists) |
|
| PlaylistCacheCleanDelay | PLAYLIST_CACHE_CLEAN_DELAY | 5 minutes | Time between each cleanup of the cache (to remove expired playlists) |
|
||||||
| UserAgent | USER_AGENT | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3 | User-Agent header used for requests to SoundCloud |
|
| UserAgent | USER_AGENT | Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.3 | User-Agent header used for requests to SoundCloud |
|
||||||
| DNSCacheTTL | DNS_CACHE_TTL | 60 minutes | Time until DNS cache expires |
|
| DNSCacheTTL | DNS_CACHE_TTL | 60 minutes | Time until DNS cache expires |
|
||||||
| Addr | ADDR | :4664 | Address and port for soundcloak to listen on |
|
| Addr | ADDR | :4664 | Address and port for soundcloak to listen on |
|
||||||
| Prefork | PREFORK | false | Run multiple instances of soundcloak locally to be able to handle more requests. Each one will be a separate process, so they will have separate cache. |
|
| Prefork | PREFORK | false | Run multiple instances of soundcloak locally to be able to handle more requests. Each one will be a separate process, so they will have separate cache. |
|
||||||
| TrustedProxyCheck | TRUSTED_PROXY_CHECK | true | Use X-Forwarded-* headers if IP is in TrustedProxies list. When disabled, those headers will blindly be used. |
|
| TrustedProxyCheck | TRUSTED_PROXY_CHECK | true | Use X-Forwarded-* headers if IP is in TrustedProxies list. When disabled, those headers will blindly be used. |
|
||||||
| TrustedProxies | TRUSTED_PROXIES | [] | List of IPs or IP ranges of trusted proxies |
|
| TrustedProxies | TRUSTED_PROXIES | [] | List of IPs or IP ranges of trusted proxies |
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,13 @@ const (
|
|||||||
NonePlayer string = "none"
|
NonePlayer string = "none"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Just plays every song in order, one after another
|
||||||
|
AutoplayNormal string = "normal"
|
||||||
|
// Randomly selects a song to play from the playlist
|
||||||
|
AutoplayRandom string = "random"
|
||||||
|
)
|
||||||
|
|
||||||
type Preferences struct {
|
type Preferences struct {
|
||||||
Player *string
|
Player *string
|
||||||
ProxyStreams *bool
|
ProxyStreams *bool
|
||||||
@@ -41,6 +48,8 @@ type Preferences struct {
|
|||||||
|
|
||||||
// Automatically play next track in playlists
|
// Automatically play next track in playlists
|
||||||
AutoplayNextTrack *bool
|
AutoplayNextTrack *bool
|
||||||
|
|
||||||
|
DefaultAutoplayMode *string
|
||||||
}
|
}
|
||||||
|
|
||||||
// // config // //
|
// // config // //
|
||||||
@@ -123,6 +132,7 @@ var TrustedProxies = []string{}
|
|||||||
// ProxyImages: same as ProxyImages in your config (false by default)
|
// ProxyImages: same as ProxyImages in your config (false by default)
|
||||||
// ParseDescriptions: true
|
// ParseDescriptions: true
|
||||||
// AutoplayNextTrack: false
|
// AutoplayNextTrack: false
|
||||||
|
// DefaultAutoplayMode: AutoplayNormal
|
||||||
func defaultPreferences() {
|
func defaultPreferences() {
|
||||||
var p string
|
var p string
|
||||||
if Restream {
|
if Restream {
|
||||||
@@ -134,19 +144,18 @@ func defaultPreferences() {
|
|||||||
|
|
||||||
DefaultPreferences.ProxyStreams = &ProxyStreams
|
DefaultPreferences.ProxyStreams = &ProxyStreams
|
||||||
|
|
||||||
var f bool
|
DefaultPreferences.FullyPreloadTrack = &False
|
||||||
var t = true
|
|
||||||
DefaultPreferences.FullyPreloadTrack = &f
|
|
||||||
|
|
||||||
DefaultPreferences.ProxyImages = &ProxyImages
|
DefaultPreferences.ProxyImages = &ProxyImages
|
||||||
|
|
||||||
DefaultPreferences.ParseDescriptions = &t
|
DefaultPreferences.ParseDescriptions = &True
|
||||||
DefaultPreferences.AutoplayNextTrack = &f
|
DefaultPreferences.AutoplayNextTrack = &False
|
||||||
|
|
||||||
|
p2 := AutoplayNormal
|
||||||
|
DefaultPreferences.DefaultAutoplayMode = &p2
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDefaultPreferences(loaded Preferences) {
|
func loadDefaultPreferences(loaded Preferences) {
|
||||||
var f bool
|
|
||||||
var t = true
|
|
||||||
if loaded.Player != nil {
|
if loaded.Player != nil {
|
||||||
DefaultPreferences.Player = loaded.Player
|
DefaultPreferences.Player = loaded.Player
|
||||||
} else {
|
} else {
|
||||||
@@ -168,7 +177,7 @@ func loadDefaultPreferences(loaded Preferences) {
|
|||||||
if loaded.FullyPreloadTrack != nil {
|
if loaded.FullyPreloadTrack != nil {
|
||||||
DefaultPreferences.FullyPreloadTrack = loaded.FullyPreloadTrack
|
DefaultPreferences.FullyPreloadTrack = loaded.FullyPreloadTrack
|
||||||
} else {
|
} else {
|
||||||
DefaultPreferences.FullyPreloadTrack = &f
|
DefaultPreferences.FullyPreloadTrack = &False
|
||||||
}
|
}
|
||||||
|
|
||||||
if loaded.ProxyImages != nil {
|
if loaded.ProxyImages != nil {
|
||||||
@@ -180,13 +189,20 @@ func loadDefaultPreferences(loaded Preferences) {
|
|||||||
if loaded.ParseDescriptions != nil {
|
if loaded.ParseDescriptions != nil {
|
||||||
DefaultPreferences.ParseDescriptions = loaded.ParseDescriptions
|
DefaultPreferences.ParseDescriptions = loaded.ParseDescriptions
|
||||||
} else {
|
} else {
|
||||||
DefaultPreferences.ParseDescriptions = &t
|
DefaultPreferences.ParseDescriptions = &True
|
||||||
}
|
}
|
||||||
|
|
||||||
if loaded.AutoplayNextTrack != nil {
|
if loaded.AutoplayNextTrack != nil {
|
||||||
DefaultPreferences.AutoplayNextTrack = loaded.AutoplayNextTrack
|
DefaultPreferences.AutoplayNextTrack = loaded.AutoplayNextTrack
|
||||||
} else {
|
} else {
|
||||||
DefaultPreferences.AutoplayNextTrack = &f
|
DefaultPreferences.AutoplayNextTrack = &False
|
||||||
|
}
|
||||||
|
|
||||||
|
if loaded.DefaultAutoplayMode != nil {
|
||||||
|
DefaultPreferences.DefaultAutoplayMode = loaded.DefaultAutoplayMode
|
||||||
|
} else {
|
||||||
|
p := AutoplayNormal
|
||||||
|
DefaultPreferences.DefaultAutoplayMode = &p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,3 +511,6 @@ func init() {
|
|||||||
// seems soundcloud has 4 of these (i1, i2, i3, i4)
|
// seems soundcloud has 4 of these (i1, i2, i3, i4)
|
||||||
// they point to the same ip from my observations, and they all serve the same files
|
// they point to the same ip from my observations, and they all serve the same files
|
||||||
const ImageCDN = "i1.sndcdn.com"
|
const ImageCDN = "i1.sndcdn.com"
|
||||||
|
|
||||||
|
var True = true
|
||||||
|
var False = false
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ func Defaults(dst *cfg.Preferences) {
|
|||||||
if dst.AutoplayNextTrack == nil {
|
if dst.AutoplayNextTrack == nil {
|
||||||
dst.AutoplayNextTrack = cfg.DefaultPreferences.AutoplayNextTrack
|
dst.AutoplayNextTrack = cfg.DefaultPreferences.AutoplayNextTrack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dst.DefaultAutoplayMode == nil {
|
||||||
|
dst.DefaultAutoplayMode = cfg.DefaultPreferences.DefaultAutoplayMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(c *fiber.Ctx) (cfg.Preferences, error) {
|
func Get(c *fiber.Ctx) (cfg.Preferences, error) {
|
||||||
@@ -50,12 +54,13 @@ func Get(c *fiber.Ctx) (cfg.Preferences, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PrefsForm struct {
|
type PrefsForm struct {
|
||||||
ProxyImages string
|
ProxyImages string
|
||||||
ParseDescriptions string
|
ParseDescriptions string
|
||||||
Player string
|
Player string
|
||||||
ProxyStreams string
|
ProxyStreams string
|
||||||
FullyPreloadTrack string
|
FullyPreloadTrack string
|
||||||
AutoplayNextTrack string
|
AutoplayNextTrack string
|
||||||
|
DefaultAutoplayMode string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(r fiber.Router) {
|
func Load(r fiber.Router) {
|
||||||
@@ -81,27 +86,25 @@ func Load(r fiber.Router) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var f bool
|
|
||||||
var t bool = true
|
|
||||||
if *old.Player == "hls" {
|
if *old.Player == "hls" {
|
||||||
if cfg.ProxyStreams {
|
if cfg.ProxyStreams {
|
||||||
if p.ProxyStreams == "on" {
|
if p.ProxyStreams == "on" {
|
||||||
old.ProxyStreams = &cfg.ProxyStreams // true!
|
old.ProxyStreams = &cfg.ProxyStreams // true!
|
||||||
} else if p.ProxyStreams == "" {
|
} else if p.ProxyStreams == "" {
|
||||||
old.ProxyStreams = &f
|
old.ProxyStreams = &cfg.False
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.AutoplayNextTrack == "on" {
|
if p.AutoplayNextTrack == "on" {
|
||||||
old.AutoplayNextTrack = &t
|
old.AutoplayNextTrack = &cfg.True
|
||||||
} else {
|
} else {
|
||||||
old.AutoplayNextTrack = &f
|
old.AutoplayNextTrack = &cfg.False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.FullyPreloadTrack == "on" {
|
if p.FullyPreloadTrack == "on" {
|
||||||
old.FullyPreloadTrack = &t
|
old.FullyPreloadTrack = &cfg.True
|
||||||
} else if p.FullyPreloadTrack == "" {
|
} else if p.FullyPreloadTrack == "" {
|
||||||
old.FullyPreloadTrack = &f
|
old.FullyPreloadTrack = &cfg.False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,14 +112,18 @@ func Load(r fiber.Router) {
|
|||||||
if p.ProxyImages == "on" {
|
if p.ProxyImages == "on" {
|
||||||
old.ProxyImages = &cfg.ProxyImages // true!
|
old.ProxyImages = &cfg.ProxyImages // true!
|
||||||
} else if p.ProxyImages == "" {
|
} else if p.ProxyImages == "" {
|
||||||
old.ProxyImages = &f
|
old.ProxyImages = &cfg.False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ParseDescriptions == "on" {
|
if p.ParseDescriptions == "on" {
|
||||||
old.ParseDescriptions = &t
|
old.ParseDescriptions = &cfg.True
|
||||||
} else {
|
} else {
|
||||||
old.ParseDescriptions = &f
|
old.ParseDescriptions = &cfg.False
|
||||||
|
}
|
||||||
|
|
||||||
|
if *old.AutoplayNextTrack {
|
||||||
|
old.DefaultAutoplayMode = &p.DefaultAutoplayMode
|
||||||
}
|
}
|
||||||
old.Player = &p.Player
|
old.Player = &p.Player
|
||||||
|
|
||||||
|
|||||||
25
main.go
25
main.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -369,33 +370,39 @@ func main() {
|
|||||||
|
|
||||||
var playlist *sc.Playlist
|
var playlist *sc.Playlist
|
||||||
var nextTrack *sc.Track
|
var nextTrack *sc.Track
|
||||||
|
mode := c.Query("mode", *prefs.DefaultAutoplayMode)
|
||||||
if pl := c.Query("playlist"); pl != "" {
|
if pl := c.Query("playlist"); pl != "" {
|
||||||
p, err := sc.GetPlaylist(pl)
|
p, err := sc.GetPlaylist(pl)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error getting %s playlist (track): %s\n", pl, err)
|
log.Printf("error getting %s playlist (track): %s\n", pl, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.Tracks = p.Postfix(prefs, true, false)
|
||||||
|
|
||||||
nextIndex := -1
|
nextIndex := -1
|
||||||
for i, t := range p.Tracks {
|
if mode == cfg.AutoplayRandom {
|
||||||
if t.ID == track.ID {
|
nextIndex = rand.Intn(len(p.Tracks))
|
||||||
nextIndex = i + 1
|
} else {
|
||||||
|
for i, t := range p.Tracks {
|
||||||
|
if t.ID == track.ID {
|
||||||
|
nextIndex = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextIndex == len(p.Tracks) {
|
||||||
|
nextIndex = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if nextIndex != -1 {
|
if nextIndex != -1 {
|
||||||
if nextIndex == len(p.Tracks) {
|
|
||||||
nextIndex = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
nextTrack = &p.Tracks[nextIndex]
|
nextTrack = &p.Tracks[nextIndex]
|
||||||
playlist = &p
|
playlist = &p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Set("Content-Type", "text/html")
|
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")), templates.TrackHeader(prefs, track)).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), templates.TrackHeader(prefs, track)).Render(context.Background(), c)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Get("/:user", func(c *fiber.Ctx) error {
|
app.Get("/:user", func(c *fiber.Ctx) error {
|
||||||
|
|||||||
@@ -72,6 +72,16 @@ templ Preferences(prefs cfg.Preferences) {
|
|||||||
Autoplay next track in playlists:
|
Autoplay next track in playlists:
|
||||||
@checkbox("AutoplayNextTrack", *prefs.AutoplayNextTrack)
|
@checkbox("AutoplayNextTrack", *prefs.AutoplayNextTrack)
|
||||||
</label>
|
</label>
|
||||||
|
if *prefs.AutoplayNextTrack {
|
||||||
|
<br/>
|
||||||
|
<label>
|
||||||
|
Default autoplay mode:
|
||||||
|
@sel("DefaultAutoplayMode", []option{
|
||||||
|
{"normal", "Normal (play songs in order)", false},
|
||||||
|
{"random", "Random (play random song)", false},
|
||||||
|
}, *prefs.DefaultAutoplayMode)
|
||||||
|
</label>
|
||||||
|
}
|
||||||
<br/>
|
<br/>
|
||||||
}
|
}
|
||||||
<input type="submit" value="Update" class="btn" style="margin-top: 1rem;"/>
|
<input type="submit" value="Update" class="btn" style="margin-top: 1rem;"/>
|
||||||
|
|||||||
@@ -19,11 +19,21 @@ templ TrackHeader(prefs cfg.Preferences, t sc.Track) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func next(t *sc.Track, p *sc.Playlist) string {
|
func next(t *sc.Track, p *sc.Playlist, autoplay bool, mode string, volume string) string {
|
||||||
return t.Href() + "?autoplay=true&playlist=" + p.Href()[1:]
|
r := t.Href() + "?playlist=" + p.Href()[1:]
|
||||||
|
if autoplay {
|
||||||
|
r += "&autoplay=true"
|
||||||
|
}
|
||||||
|
if mode != "" {
|
||||||
|
r += "&mode=" + mode
|
||||||
|
}
|
||||||
|
if volume != "" {
|
||||||
|
r += "&volume=" + volume
|
||||||
|
}
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayErr string, autoplay bool, nextTrack *sc.Track, playlist *sc.Playlist, volume string) {
|
templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayErr string, autoplay bool, nextTrack *sc.Track, playlist *sc.Playlist, volume string, mode string) {
|
||||||
if *prefs.Player == cfg.NonePlayer {
|
if *prefs.Player == cfg.NonePlayer {
|
||||||
{{ return }}
|
{{ return }}
|
||||||
}
|
}
|
||||||
@@ -32,7 +42,7 @@ templ TrackPlayer(prefs cfg.Preferences, track sc.Track, stream string, displayE
|
|||||||
<audio src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
|
<audio src={ "/_/restream" + track.Href() } controls autoplay?={ autoplay }></audio>
|
||||||
} else if stream != "" {
|
} else if stream != "" {
|
||||||
if nextTrack != nil {
|
if nextTrack != nil {
|
||||||
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={next(nextTrack, playlist)} volume={volume}></audio>
|
<audio id="track" src={ stream } controls autoplay?={ autoplay } data-next={next(nextTrack, playlist, true, mode, "")} volume={volume}></audio>
|
||||||
} else {
|
} else {
|
||||||
<audio id="track" src={ stream } controls autoplay?={ autoplay }></audio>
|
<audio id="track" src={ stream } controls autoplay?={ autoplay }></audio>
|
||||||
}
|
}
|
||||||
@@ -78,12 +88,12 @@ templ TrackItem(track *sc.Track, showUsername bool, overrideHref string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string, autoplay bool, playlist *sc.Playlist, nextTrack *sc.Track, volume string) {
|
templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string, autoplay bool, playlist *sc.Playlist, nextTrack *sc.Track, volume string, mode string) {
|
||||||
if t.Artwork != "" {
|
if t.Artwork != "" {
|
||||||
<img src={ t.Artwork } width="300px"/>
|
<img src={ t.Artwork } width="300px"/>
|
||||||
}
|
}
|
||||||
<h1>{ t.Title }</h1>
|
<h1>{ t.Title }</h1>
|
||||||
@TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume)
|
@TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume, mode)
|
||||||
if t.Genre != "" {
|
if t.Genre != "" {
|
||||||
<p class="tag">{ t.Genre }</p>
|
<p class="tag">{ t.Genre }</p>
|
||||||
} else {
|
} else {
|
||||||
@@ -91,16 +101,22 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
|
|||||||
<br/>
|
<br/>
|
||||||
}
|
}
|
||||||
if playlist != nil {
|
if playlist != nil {
|
||||||
<details style="margin-bottom: 1rem;">
|
<details open style="margin-bottom: 1rem;">
|
||||||
<summary>Playback info</summary>
|
<summary>Playback info</summary>
|
||||||
|
|
||||||
<h2>In playlist:</h2>
|
<h2>In playlist:</h2>
|
||||||
@PlaylistItem(playlist, true)
|
@PlaylistItem(playlist, true)
|
||||||
|
|
||||||
<h2>Next track:</h2>
|
<h2>Next track:</h2>
|
||||||
@TrackItem(nextTrack, true, next(nextTrack, playlist) + "&volume=" + volume)
|
@TrackItem(nextTrack, true, next(nextTrack, playlist, true, mode, volume))
|
||||||
|
|
||||||
<a href={templ.URL(t.Href())} class="link">Stop playlist playback</a>
|
<a href={templ.URL(t.Href())} class="link">Stop playlist playback</a>
|
||||||
|
<br>
|
||||||
|
if mode != cfg.AutoplayRandom {
|
||||||
|
<a href={templ.URL(next(&t, playlist, false, cfg.AutoplayRandom, volume))} class="link">Switch to random mode</a>
|
||||||
|
} else {
|
||||||
|
<a href={templ.URL(next(&t, playlist, false, cfg.AutoplayNormal, volume))} class="link">Switch to normal mode</a>
|
||||||
|
}
|
||||||
</details>
|
</details>
|
||||||
}
|
}
|
||||||
@UserItem(&t.Author)
|
@UserItem(&t.Author)
|
||||||
@@ -142,7 +158,7 @@ templ TrackEmbed(prefs cfg.Preferences, t sc.Track, stream string, displayErr st
|
|||||||
<img src={ t.Artwork } width="300px"/>
|
<img src={ t.Artwork } width="300px"/>
|
||||||
}
|
}
|
||||||
<h1>{ t.Title }</h1>
|
<h1>{ t.Title }</h1>
|
||||||
@TrackPlayer(prefs, t, stream, displayErr, false, nil, nil, "")
|
@TrackPlayer(prefs, t, stream, displayErr, false, nil, nil, "", "")
|
||||||
@UserItem(&t.Author)
|
@UserItem(&t.Author)
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user