Shuffle mode for autoplay; fix proxying with autoplay

This commit is contained in:
Laptop
2024-12-04 20:52:53 +02:00
parent 96ac9c8b36
commit f3b466f18f
6 changed files with 127 additions and 68 deletions

View File

@@ -38,7 +38,7 @@ Available features:
- - 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
- - 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
Contributions are appreciated! This includes feedback, feature requests, issues, pull requests and etc.
@@ -190,10 +190,10 @@ 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, "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) |
| 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 |

View File

@@ -25,6 +25,13 @@ const (
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 {
Player *string
ProxyStreams *bool
@@ -41,6 +48,8 @@ type Preferences struct {
// Automatically play next track in playlists
AutoplayNextTrack *bool
DefaultAutoplayMode *string
}
// // config // //
@@ -123,6 +132,7 @@ var TrustedProxies = []string{}
// ProxyImages: same as ProxyImages in your config (false by default)
// ParseDescriptions: true
// AutoplayNextTrack: false
// DefaultAutoplayMode: AutoplayNormal
func defaultPreferences() {
var p string
if Restream {
@@ -134,19 +144,18 @@ func defaultPreferences() {
DefaultPreferences.ProxyStreams = &ProxyStreams
var f bool
var t = true
DefaultPreferences.FullyPreloadTrack = &f
DefaultPreferences.FullyPreloadTrack = &False
DefaultPreferences.ProxyImages = &ProxyImages
DefaultPreferences.ParseDescriptions = &t
DefaultPreferences.AutoplayNextTrack = &f
DefaultPreferences.ParseDescriptions = &True
DefaultPreferences.AutoplayNextTrack = &False
p2 := AutoplayNormal
DefaultPreferences.DefaultAutoplayMode = &p2
}
func loadDefaultPreferences(loaded Preferences) {
var f bool
var t = true
if loaded.Player != nil {
DefaultPreferences.Player = loaded.Player
} else {
@@ -168,7 +177,7 @@ func loadDefaultPreferences(loaded Preferences) {
if loaded.FullyPreloadTrack != nil {
DefaultPreferences.FullyPreloadTrack = loaded.FullyPreloadTrack
} else {
DefaultPreferences.FullyPreloadTrack = &f
DefaultPreferences.FullyPreloadTrack = &False
}
if loaded.ProxyImages != nil {
@@ -180,13 +189,20 @@ func loadDefaultPreferences(loaded Preferences) {
if loaded.ParseDescriptions != nil {
DefaultPreferences.ParseDescriptions = loaded.ParseDescriptions
} else {
DefaultPreferences.ParseDescriptions = &t
DefaultPreferences.ParseDescriptions = &True
}
if loaded.AutoplayNextTrack != nil {
DefaultPreferences.AutoplayNextTrack = loaded.AutoplayNextTrack
} 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)
// they point to the same ip from my observations, and they all serve the same files
const ImageCDN = "i1.sndcdn.com"
var True = true
var False = false

View File

@@ -34,6 +34,10 @@ func Defaults(dst *cfg.Preferences) {
if dst.AutoplayNextTrack == nil {
dst.AutoplayNextTrack = cfg.DefaultPreferences.AutoplayNextTrack
}
if dst.DefaultAutoplayMode == nil {
dst.DefaultAutoplayMode = cfg.DefaultPreferences.DefaultAutoplayMode
}
}
func Get(c *fiber.Ctx) (cfg.Preferences, error) {
@@ -56,6 +60,7 @@ type PrefsForm struct {
ProxyStreams string
FullyPreloadTrack string
AutoplayNextTrack string
DefaultAutoplayMode string
}
func Load(r fiber.Router) {
@@ -81,27 +86,25 @@ func Load(r fiber.Router) {
return err
}
var f bool
var t bool = true
if *old.Player == "hls" {
if cfg.ProxyStreams {
if p.ProxyStreams == "on" {
old.ProxyStreams = &cfg.ProxyStreams // true!
} else if p.ProxyStreams == "" {
old.ProxyStreams = &f
old.ProxyStreams = &cfg.False
}
if p.AutoplayNextTrack == "on" {
old.AutoplayNextTrack = &t
old.AutoplayNextTrack = &cfg.True
} else {
old.AutoplayNextTrack = &f
old.AutoplayNextTrack = &cfg.False
}
}
if p.FullyPreloadTrack == "on" {
old.FullyPreloadTrack = &t
old.FullyPreloadTrack = &cfg.True
} else if p.FullyPreloadTrack == "" {
old.FullyPreloadTrack = &f
old.FullyPreloadTrack = &cfg.False
}
}
@@ -109,14 +112,18 @@ func Load(r fiber.Router) {
if p.ProxyImages == "on" {
old.ProxyImages = &cfg.ProxyImages // true!
} else if p.ProxyImages == "" {
old.ProxyImages = &f
old.ProxyImages = &cfg.False
}
}
if p.ParseDescriptions == "on" {
old.ParseDescriptions = &t
old.ParseDescriptions = &cfg.True
} else {
old.ParseDescriptions = &f
old.ParseDescriptions = &cfg.False
}
if *old.AutoplayNextTrack {
old.DefaultAutoplayMode = &p.DefaultAutoplayMode
}
old.Player = &p.Player

13
main.go
View File

@@ -3,6 +3,7 @@ package main
import (
"context"
"log"
"math/rand"
"net/url"
"strings"
@@ -369,33 +370,39 @@ func main() {
var playlist *sc.Playlist
var nextTrack *sc.Track
mode := c.Query("mode", *prefs.DefaultAutoplayMode)
if pl := c.Query("playlist"); pl != "" {
p, err := sc.GetPlaylist(pl)
if err != nil {
log.Printf("error getting %s playlist (track): %s\n", pl, err)
return err
}
p.Tracks = p.Postfix(prefs, true, false)
nextIndex := -1
if mode == cfg.AutoplayRandom {
nextIndex = rand.Intn(len(p.Tracks))
} else {
for i, t := range p.Tracks {
if t.ID == track.ID {
nextIndex = i + 1
}
}
if nextIndex != -1 {
if nextIndex == len(p.Tracks) {
nextIndex = 0
}
}
if nextIndex != -1 {
nextTrack = &p.Tracks[nextIndex]
playlist = &p
}
}
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 {

View File

@@ -72,6 +72,16 @@ templ Preferences(prefs cfg.Preferences) {
Autoplay next track in playlists:
@checkbox("AutoplayNextTrack", *prefs.AutoplayNextTrack)
</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/>
}
<input type="submit" value="Update" class="btn" style="margin-top: 1rem;"/>

View File

@@ -19,11 +19,21 @@ templ TrackHeader(prefs cfg.Preferences, t sc.Track) {
}
}
func next(t *sc.Track, p *sc.Playlist) string {
return t.Href() + "?autoplay=true&playlist=" + p.Href()[1:]
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"
}
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 {
{{ 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>
} else if stream != "" {
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 {
<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 != "" {
<img src={ t.Artwork } width="300px"/>
}
<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 != "" {
<p class="tag">{ t.Genre }</p>
} else {
@@ -91,16 +101,22 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
<br/>
}
if playlist != nil {
<details style="margin-bottom: 1rem;">
<details open style="margin-bottom: 1rem;">
<summary>Playback info</summary>
<h2>In playlist:</h2>
@PlaylistItem(playlist, true)
<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>
<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>
}
@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"/>
}
<h1>{ t.Title }</h1>
@TrackPlayer(prefs, t, stream, displayErr, false, nil, nil, "")
@TrackPlayer(prefs, t, stream, displayErr, false, nil, nil, "", "")
@UserItem(&t.Author)
</body>
</html>