aboutsummaryrefslogtreecommitdiff
path: root/spotify.go
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2023-07-23 15:09:17 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2023-07-23 15:09:17 +0200
commit7d097ff3d18159907698e6af9be5f8ed8bc79cd9 (patch)
treecab483dc679096a67c45f8a1d9362cc76370bb19 /spotify.go
parent86295f229a2b215b36053424b5b067fde549bd8f (diff)
downloadWRMS-7d097ff3d18159907698e6af9be5f8ed8bc79cd9.tar.gz
WRMS-7d097ff3d18159907698e6af9be5f8ed8bc79cd9.zip
implement advanced search for the spotify backend
The librespot API does not allow advanced search therefore we filter the results according to our advanced patterns.
Diffstat (limited to 'spotify.go')
-rw-r--r--spotify.go116
1 files changed, 88 insertions, 28 deletions
diff --git a/spotify.go b/spotify.go
index e15501a..7c5c298 100644
--- a/spotify.go
+++ b/spotify.go
@@ -9,7 +9,9 @@ package main
import (
"errors"
+ "fmt"
"os"
+ "regexp"
"strings"
"github.com/librespot-org/librespot-golang/Spotify"
@@ -21,7 +23,9 @@ import (
)
const (
- deviceName = "wrms"
+ deviceName = "wrms"
+ searchResults = 25
+ displayedSearchResults = 10
)
type SpotifyConfig struct {
@@ -30,11 +34,16 @@ type SpotifyConfig struct {
}
type SpotifyBackend struct {
- session *core.Session
+ session *core.Session
+ searchResults int
+ displayedSearchResults int
}
func NewSpotify(config *SpotifyConfig) (*SpotifyBackend, error) {
- spotify := SpotifyBackend{}
+ spotify := SpotifyBackend{
+ searchResults: searchResults,
+ displayedSearchResults: displayedSearchResults}
+
if config == nil {
config = &SpotifyConfig{}
}
@@ -98,39 +107,90 @@ func (spotify *SpotifyBackend) Play(song *Song, player Player) {
func (spotify *SpotifyBackend) Search(patterns map[string]string) []*Song {
session := spotify.session
- keyword := ""
+ results := []*Song{}
+ resultMap := make(map[string]struct{})
+
for _, p := range []string{"pattern", "title", "artist", "album"} {
- if v, ok := patterns[p]; ok {
- keyword = v
- break
+ pattern, ok := patterns[p]
+ if !ok {
+ continue
}
- }
- resp, err := session.Mercury().Search(keyword, 12, session.Country(), session.Username())
-
- if err != nil {
- llog.Error("Failed to search: %s", err)
- return nil
- }
+ resp, err := session.Mercury().Search(pattern,
+ spotify.searchResults,
+ session.Country(),
+ session.Username())
- res := resp.Results
+ if err != nil {
+ llog.Error("Failed to search: %s", err)
+ return nil
+ }
- llog.DDebug("Search results for %s", keyword)
- llog.DDebug("=============================")
+ res := resp.Results
+ llog.DDebug("Search results for %v", pattern)
+ llog.DDebug("=============================")
- if res.Error != nil {
- llog.Error("Search result error: %s", res.Error)
+ if res.Error != nil {
+ llog.Error("Search result error: %s", res.Error)
+ }
+ llog.DDebug("\nTracks: %d (total %d)\n", len(res.Tracks.Hits), res.Tracks.Total)
+
+ out:
+ for _, track := range res.Tracks.Hits {
+ // filter matching tracks
+ for _, cond := range []string{"pattern", "title", "artist", "album"} {
+ cond_pattern, ok := patterns[cond]
+ if !ok {
+ continue
+ }
+
+ simpleMatch, err := regexp.Compile(fmt.Sprintf(".*%s.*", cond_pattern))
+ if err != nil {
+ llog.Fatal("Failed to compile matching regex '%s': %v",
+ fmt.Sprintf(".*%s.*", cond_pattern), err)
+ }
+
+ switch cond {
+ case "title":
+ if !simpleMatch.MatchString(track.Name) {
+ continue out
+ }
+
+ case "album":
+ if !simpleMatch.MatchString(track.Album.Name) {
+ continue out
+ }
+
+ case "artist":
+ matchingArtist := false
+ for _, a := range track.Artists {
+ if simpleMatch.MatchString(a.Name) {
+ matchingArtist = true
+ break
+ }
+ }
+
+ if !matchingArtist {
+ continue out
+ }
+ }
+ }
+
+ uriParts := strings.Split(track.Uri, ":")
+ uri := uriParts[len(uriParts)-1]
+
+ if _, ok := resultMap[uri]; !ok {
+ s := NewSong(track.Name, track.Artists[0].Name, "spotify", uri)
+ s.Album = track.Album.Name
+ resultMap[uri] = struct{}{}
+ results = append(results, s)
+ }
+ }
}
- llog.Debug("\nTracks: %d (total %d)\n", len(res.Tracks.Hits), res.Tracks.Total)
-
- results := []*Song{}
- for _, track := range res.Tracks.Hits {
- uriParts := strings.Split(track.Uri, ":")
- s := NewSong(track.Name, track.Artists[0].Name, "spotify", uriParts[len(uriParts)-1])
- s.Album = track.Album.Name
- results = append(results, s)
+ // Think about a way to better sort ther results by relevance
+ if len(results) > spotify.displayedSearchResults {
+ return results[:spotify.displayedSearchResults]
}
-
return results
}