aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md2
-rw-r--r--config.go1
-rw-r--r--main.go5
-rw-r--r--player.go9
-rw-r--r--spotify.go53
-rw-r--r--wrms.go30
6 files changed, 95 insertions, 5 deletions
diff --git a/TODO.md b/TODO.md
index 14f5707..798a1e7 100644
--- a/TODO.md
+++ b/TODO.md
@@ -39,7 +39,7 @@
- [X] Fix youtube search
- [ ] Support loading playlists
- [ ] m3u
- - [ ] spotify playlist
+ - [X] spotify playlist
## Configuration
diff --git a/config.go b/config.go
index 32b94ca..b2df159 100644
--- a/config.go
+++ b/config.go
@@ -14,6 +14,7 @@ import (
type Config struct {
Port int `yaml:"port"`
Backends []string `yaml:"backends"`
+ Playlists []string `yaml:"playlists"`
LocalMusicDir string `yaml:"music-dir"`
UploadDir string `yaml:"upload-dir"`
LogLevel string `yaml:"loglevel"`
diff --git a/main.go b/main.go
index 8c70976..c627894 100644
--- a/main.go
+++ b/main.go
@@ -275,12 +275,17 @@ func main() {
flag.StringVar(&config.LocalMusicDir,
"serve-music-dir", config.LocalMusicDir, "local music directory to serve")
flag.StringVar(&config.UploadDir, "upload-dir", config.UploadDir, "directory to upload songs to")
+ playlists := flag.String("playlists", "", "playlists to load")
flag.Parse()
if *backends != "" {
config.Backends = strings.Split(*backends, " ")
}
+ if *playlists != "" {
+ config.Playlists = append(config.Playlists, strings.Split(*playlists, " ")...)
+ }
+
llog.SetLogLevelFromString(config.LogLevel)
config.HasUpload = slices.Contains(config.Backends, "upload")
diff --git a/player.go b/player.go
index 795978b..b8db8fa 100644
--- a/player.go
+++ b/player.go
@@ -20,6 +20,7 @@ type Player interface {
Pause()
Continue()
Stop()
+ LoadPlaylist(playlist string) []*Song
}
// command struct used to serialize player commands
@@ -253,3 +254,11 @@ func (player *MpvPlayer) Search(pattern map[string]string) chan []*Song {
return ch
}
+
+func (player *MpvPlayer) LoadPlaylist(playlist string) (songs []*Song) {
+ if strings.Contains(playlist, "spotify.com") {
+ songs = player.Backends["spotify"].(*SpotifyBackend).loadPlaylist(playlist)
+ }
+
+ return
+}
diff --git a/spotify.go b/spotify.go
index 31adf1b..3e8d962 100644
--- a/spotify.go
+++ b/spotify.go
@@ -194,3 +194,56 @@ func (spotify *SpotifyBackend) Search(patterns map[string]string) []*Song {
}
return results
}
+
+func (spotify *SpotifyBackend) loadPlaylist(playlist string) []*Song {
+ playlistIdRegex := regexp.MustCompile(`playlist/.*\?`)
+ match := playlistIdRegex.FindString(playlist)
+ if match == "" {
+ llog.Error("Failed to extract spotify playlist id from %s", playlist)
+ }
+
+ id := match[len("playlist/") : len(match)-1]
+ llog.Debug("Extracted id %s from spotify playlist URI %s", id, playlist)
+
+ // _pl, err := GetPlaylistV2(spotify.session.Mercury(), id)
+ _pl, err := spotify.session.Mercury().GetPlaylist(id)
+ if err != nil {
+ llog.Error("Getting playlist %s failed with %v", playlist, err)
+ return nil
+ }
+
+ plContent := _pl.GetContents()
+ if plContent == nil {
+ llog.Warning("Playlist %s has no content", playlist)
+ return nil
+ }
+
+ plItems := plContent.GetItems()
+ if plItems == nil {
+ llog.Warning("Playlist %s content has no items", playlist)
+ return nil
+ }
+
+ var songs []*Song
+ for _, item := range plItems {
+ uri := item.GetUri()
+ if uri == "" {
+ continue
+ }
+
+
+ uriParts := strings.Split(uri, ":")
+ uri = uriParts[len(uriParts)-1]
+ track, err := spotify.session.Mercury().GetTrack(utils.Base62ToHex(uri))
+ if err != nil {
+ llog.Error("Failed to load track %s: %v", uri, err)
+ }
+
+ s := NewSong(*track.Name, *track.Artist[0].Name, "spotify", uri)
+ s.Album = *track.Album.Name
+ songs = append(songs, s)
+ }
+
+ llog.Debug("Added %d songs from spotify playlist %s", len(songs), _pl.Attributes.GetName())
+ return songs
+}
diff --git a/wrms.go b/wrms.go
index 247ede8..5dfdc53 100644
--- a/wrms.go
+++ b/wrms.go
@@ -54,6 +54,11 @@ func NewWrms(config Config) *Wrms {
wrms := Wrms{}
wrms.Config = config
wrms.Player = NewMpvPlayer(&wrms, config.Backends)
+
+ if len(wrms.Config.Playlists) > 0 {
+ wrms.loadPlaylists(wrms.Config.Playlists)
+ }
+
return &wrms
}
@@ -134,6 +139,11 @@ func (wrms *Wrms) Broadcast(ev Event) {
})
}
+func (wrms *Wrms) _addSong(song *Song) {
+ wrms.Songs = append(wrms.Songs, song)
+ wrms.queue.Add(song)
+}
+
func (wrms *Wrms) AddSong(song *Song) {
wrms.rwlock.Lock()
@@ -144,14 +154,12 @@ func (wrms *Wrms) AddSong(song *Song) {
wrms.queue.applyTimeBonus(wrms.Config.timeBonus)
}
- wrms.Songs = append(wrms.Songs, song)
- s := wrms.Songs[len(wrms.Songs)-1]
- wrms.queue.Add(s)
+ wrms._addSong(song)
ev := wrms.newEvent("add", []*Song{song})
wrms.rwlock.Unlock()
- llog.Info("Added song %s (ptr=%p) to Songs", s.Uri, s)
+ llog.Info("Added song %s (ptr=%p) to Songs", song.Uri, song)
wrms.Broadcast(ev)
if startPlayingAgain {
@@ -343,3 +351,17 @@ func (wrms *Wrms) AdjustSongWeight(connId uuid.UUID, songUri string, vote string
func (wrms *Wrms) Search(pattern map[string]string) chan []*Song {
return wrms.Player.Search(pattern)
}
+
+func (wrms *Wrms) loadPlaylists(playlists []string) {
+ for _, playlist := range playlists {
+ wrms.appendPlaylist(playlist)
+ }
+}
+
+func (wrms *Wrms) appendPlaylist(playlist string) {
+ songs := wrms.Player.LoadPlaylist(playlist)
+
+ for _, song := range songs {
+ wrms._addSong(song)
+ }
+}