add settings for skipping one-star or tracks with keyword (#724)

This commit is contained in:
Drew Weymouth
2025-09-24 18:59:55 -07:00
committed by GitHub
parent d5c47b65fa
commit 4c1a95e851
6 changed files with 51 additions and 22 deletions
+32 -18
View File
@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/charlievieth/strcase"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/backend/player"
"github.com/dweymouth/supersonic/backend/player/dlna"
@@ -27,7 +28,8 @@ type PlaybackManager struct {
wfmGen *WaveformImageGenerator
cache *AudioCache
cmdQueue *playbackCommandQueue
cfg *AppConfig
appCfg *AppConfig
cfg *PlaybackConfig
localPlayer player.BasePlayer
remotePlayersLock sync.Mutex
@@ -36,8 +38,6 @@ type PlaybackManager struct {
onWaveformImgUpdate []func(*WaveformImage)
autoplay bool
lastPlayTime float64
lastPlayingID string
wfmUpdateImageCancel context.CancelFunc
@@ -66,8 +66,8 @@ func NewPlaybackManager(
pm := &PlaybackManager{
engine: e,
cmdQueue: q,
cfg: appCfg,
autoplay: playbackCfg.Autoplay,
appCfg: appCfg,
cfg: playbackCfg,
localPlayer: p,
cache: c,
}
@@ -117,7 +117,7 @@ func (p *PlaybackManager) addOnTrackChangeHook() {
p.OnSongChange(func(item mediaprovider.MediaItem, _ *mediaprovider.Track) {
// Autoplay if enabled and we are on the last track
if p.autoplay && p.NowPlayingIndex() == len(p.engine.playQueue)-1 {
if p.cfg.Autoplay && p.NowPlayingIndex() == len(p.engine.playQueue)-1 {
p.enqueueAutoplayTracks()
}
p.handleWaveformImageSongChange(item)
@@ -470,13 +470,23 @@ func (p *PlaybackManager) PlayTrackAt(idx int) {
func (p *PlaybackManager) PlayRandomSongs(genreName string) error {
return p.fetchAndPlayTracks(func() ([]*mediaprovider.Track, error) {
return p.engine.sm.Server.GetRandomTracks(genreName, p.cfg.EnqueueBatchSize)
tr, err := p.engine.sm.Server.GetRandomTracks(genreName, p.appCfg.EnqueueBatchSize)
if err != nil {
return nil, err
}
return sharedutil.FilterSlice(tr, func(t *mediaprovider.Track) bool {
skipKwd := p.cfg.SkipKeywordWhenShuffling
include :=
(skipKwd == "" || !strcase.Contains(t.Title, skipKwd)) &&
(!p.cfg.SkipOneStarWhenShuffling || t.Rating != 1)
return include
}), nil
})
}
func (p *PlaybackManager) PlaySimilarSongs(id string) error {
return p.fetchAndPlayTracks(func() ([]*mediaprovider.Track, error) {
return p.engine.sm.Server.GetSimilarTracks(id, p.cfg.EnqueueBatchSize)
return p.engine.sm.Server.GetSimilarTracks(id, p.appCfg.EnqueueBatchSize)
})
}
@@ -592,7 +602,7 @@ func (p *PlaybackManager) GetLoopMode() LoopMode {
}
func (p *PlaybackManager) IsAutoplay() bool {
return p.autoplay
return p.cfg.Autoplay
}
func (p *PlaybackManager) PlaybackStatus() PlaybackStatus {
@@ -604,7 +614,7 @@ func (p *PlaybackManager) SetVolume(vol int) {
}
func (p *PlaybackManager) SetAutoplay(autoplay bool) {
p.autoplay = autoplay
p.cfg.Autoplay = autoplay
if autoplay && p.NowPlayingIndex() == len(p.engine.playQueue)-1 {
p.enqueueAutoplayTracks()
}
@@ -705,11 +715,15 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
// tracks we will enqueue
var tracks []*mediaprovider.Track
filterRecentlyPlayed := func(tracks []*mediaprovider.Track) []*mediaprovider.Track {
filterAutoplayTracks := func(tracks []*mediaprovider.Track) []*mediaprovider.Track {
return sharedutil.FilterSlice(tracks, func(t *mediaprovider.Track) bool {
return !slices.ContainsFunc(queue, func(i mediaprovider.MediaItem) bool {
shouldSkip :=
(p.cfg.SkipOneStarWhenShuffling && t.Rating == 1) ||
(p.cfg.SkipKeywordWhenShuffling != "" && strcase.Contains(t.Title, p.cfg.SkipKeywordWhenShuffling))
recentlyPlayed := slices.ContainsFunc(queue, func(i mediaprovider.MediaItem) bool {
return i.Metadata().Type == mediaprovider.MediaItemTypeTrack && i.Metadata().ID == t.ID
})
return !shouldSkip && !recentlyPlayed
})
}
@@ -722,11 +736,11 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
// similar tracks by artist
if len(tr.ArtistIDs) > 0 {
similar, err := s.GetSimilarTracks(tr.ArtistIDs[0], p.cfg.EnqueueBatchSize)
similar, err := s.GetSimilarTracks(tr.ArtistIDs[0], p.appCfg.EnqueueBatchSize)
if err != nil {
log.Printf("autoplay error: failed to get similar tracks: %v", err)
}
tracks = filterRecentlyPlayed(similar)
tracks = filterAutoplayTracks(similar)
}
// fallback to random tracks from genre
@@ -735,11 +749,11 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
if g == "" {
continue
}
byGenre, err := s.GetRandomTracks(g, p.cfg.EnqueueBatchSize)
byGenre, err := s.GetRandomTracks(g, p.appCfg.EnqueueBatchSize)
if err != nil {
log.Printf("autoplay error: failed to get tracks by genre: %v", err)
}
tracks = filterRecentlyPlayed(byGenre)
tracks = filterAutoplayTracks(byGenre)
if len(tracks) > 0 {
break
}
@@ -750,11 +764,11 @@ func (p *PlaybackManager) enqueueAutoplayTracks() {
// random tracks works regardless of the type of the last playing media
if len(tracks) == 0 {
// fallback to random tracks
random, err := s.GetRandomTracks("", p.cfg.EnqueueBatchSize)
random, err := s.GetRandomTracks("", p.appCfg.EnqueueBatchSize)
if err != nil {
log.Printf("autoplay error: failed to get random tracks: %v", err)
}
tracks = filterRecentlyPlayed(random)
tracks = filterAutoplayTracks(random)
}
if len(tracks) > 0 {