Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 79 additions & 83 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,15 @@ func redactURL(rawUrl string) string {
return parsed.String()
}

func subsonicGET(endpoint string, params map[string]string) (*SubsonicResponse, error) {
func subsonicGET(endpoint string, params url.Values) (*SubsonicResponse, error) {
baseUrl := AppServerConfig.Server.URL + "/rest" + endpoint

v := getAuthParams()

for key, value := range params {
v.Set(key, value)
for key, values := range params {
for _, value := range values {
v.Add(key, value)
}
}

fullUrl := baseUrl + "?" + v.Encode()
Expand All @@ -121,8 +123,8 @@ func subsonicGET(endpoint string, params map[string]string) (*SubsonicResponse,
}

func SubsonicLoginCheck() error {
params := map[string]string{
"username": AppServerConfig.Server.Username,
params := url.Values{
"username": {AppServerConfig.Server.Username},
}

data, err := subsonicGET("/getUser", params)
Expand All @@ -145,14 +147,14 @@ func SubsonicLoginCheck() error {
}

func SubsonicSearchArtist(query string, offset int) ([]Artist, error) {
params := map[string]string{
"query": query,
"artistCount": "150",
"artistOffset": strconv.Itoa(offset),
"albumCount": "0",
"albumOffset": "0",
"songCount": "0",
"songOffset": "0",
params := url.Values{
"query": {query},
"artistCount": {"150"},
"artistOffset": {strconv.Itoa(offset)},
"albumCount": {"0"},
"albumOffset": {"0"},
"songCount": {"0"},
"songOffset": {"0"},
}

data, err := subsonicGET("/search3", params)
Expand All @@ -164,14 +166,14 @@ func SubsonicSearchArtist(query string, offset int) ([]Artist, error) {
}

func SubsonicSearchAlbum(query string, offset int) ([]Album, error) {
params := map[string]string{
"query": query,
"artistCount": "0",
"artistOffset": "0",
"albumCount": "150",
"albumOffset": strconv.Itoa(offset),
"songCount": "0",
"songOffset": "0",
params := url.Values{
"query": {query},
"artistCount": {"0"},
"artistOffset": {"0"},
"albumCount": {"150"},
"albumOffset": {strconv.Itoa(offset)},
"songCount": {"0"},
"songOffset": {"0"},
}

data, err := subsonicGET("/search3", params)
Expand All @@ -183,14 +185,14 @@ func SubsonicSearchAlbum(query string, offset int) ([]Album, error) {
}

func SubsonicSearchSong(query string, offset int) ([]Song, error) {
params := map[string]string{
"query": query,
"artistCount": "0",
"artistOffset": "0",
"albumCount": "0",
"albumOffset": "0",
"songCount": "150",
"songOffset": strconv.Itoa(offset),
params := url.Values{
"query": {query},
"artistCount": {"0"},
"artistOffset": {"0"},
"albumCount": {"0"},
"albumOffset": {"0"},
"songCount": {"150"},
"songOffset": {strconv.Itoa(offset)},
}

data, err := subsonicGET("/search3", params)
Expand All @@ -202,8 +204,8 @@ func SubsonicSearchSong(query string, offset int) ([]Song, error) {
}

func SubsonicGetPlaylistSongs(id string) ([]Song, error) {
params := map[string]string{
"id": id,
params := url.Values{
"id": {id},
}

data, err := subsonicGET("/getPlaylist", params)
Expand All @@ -215,7 +217,7 @@ func SubsonicGetPlaylistSongs(id string) ([]Song, error) {
}

func SubsonicGetPlaylists() ([]Playlist, error) {
params := map[string]string{}
params := url.Values{}

data, err := subsonicGET("/getPlaylists", params)
if err != nil {
Expand All @@ -226,8 +228,8 @@ func SubsonicGetPlaylists() ([]Playlist, error) {
}

func SubsonicGetAlbum(id string) ([]Song, error) {
params := map[string]string{
"id": id,
params := url.Values{
"id": {id},
}

data, err := subsonicGET("/getAlbum", params)
Expand All @@ -239,10 +241,10 @@ func SubsonicGetAlbum(id string) ([]Song, error) {
}

func SubsonicGetAlbumList(searchType string, offset int) ([]Album, error) {
params := map[string]string{
"type": searchType,
"size": "150",
"offset": strconv.Itoa(offset),
params := url.Values{
"type": {searchType},
"size": {"150"},
"offset": {strconv.Itoa(offset)},
}

data, err := subsonicGET("/getAlbumList", params)
Expand All @@ -254,8 +256,8 @@ func SubsonicGetAlbumList(searchType string, offset int) ([]Album, error) {
}

func SubsonicGetArtist(id string) ([]Album, error) {
params := map[string]string{
"id": id,
params := url.Values{
"id": {id},
}

data, err := subsonicGET("/getArtist", params)
Expand All @@ -266,17 +268,19 @@ func SubsonicGetArtist(id string) ([]Album, error) {
return data.Response.Artist.Albums, nil
}

func SubsonicStar(id string) {
params := map[string]string{
"id": id,
func SubsonicStar(ids []string) {
params := url.Values{}
for _, id := range ids {
params.Add("id", id)
}

_, _ = subsonicGET("/star", params)
}

func SubsonicUnstar(id string) {
params := map[string]string{
"id": id,
func SubsonicUnstar(ids []string) {
params := url.Values{}
for _, id := range ids {
params.Add("id", id)
}

_, _ = subsonicGET("/unstar", params)
Expand All @@ -296,9 +300,9 @@ func SubsonicGetStarred() (*SearchResult3, error) {
}

func SubsonicRate(ID string, rating int) {
params := map[string]string{
"id": ID,
"rating": strconv.Itoa(rating),
params := url.Values{
"id": {ID},
"rating": {strconv.Itoa(rating)},
}

_, _ = subsonicGET("/setRating", params)
Expand All @@ -320,10 +324,10 @@ func SubsonicStream(id string) string {
func SubsonicScrobble(id string, submission bool) {
time := strconv.FormatInt(time.Now().UTC().UnixMilli(), 10)

params := map[string]string{
"id": id,
"time": time,
"submission": strconv.FormatBool(submission),
params := url.Values{
"id": {id},
"time": {time},
"submission": {strconv.FormatBool(submission)},
}

_, _ = subsonicGET("/scrobble", params)
Expand Down Expand Up @@ -361,29 +365,19 @@ func SubsonicCoverArt(id string, size int) ([]byte, error) {
}

func SubsonicSaveQueue(ids []string, currentID string) {
baseUrl := AppServerConfig.Server.URL + "/rest/savePlayQueue"

v := getAuthParams()

v.Set("current", currentID)
for _, id := range ids {
v.Add("id", id)
params := url.Values{
"current": {currentID},
}

url := baseUrl + "?" + v.Encode()

log.Printf("[API] Request: %s", redactURL(url))
resp, err := httpClient.Get(url)
if err != nil {
log.Printf("[API] Failed to save queue: %v", err)
return
for _, id := range ids {
params.Add("id", id)
}

defer func() { _ = resp.Body.Close() }()
_, _ = subsonicGET("/savePlayQueue", params)
}

func SubsonicGetQueue() (*PlayQueue, error) {
params := map[string]string{}
params := url.Values{}

data, err := subsonicGET("/getPlayQueue", params)
if err != nil {
Expand All @@ -393,35 +387,37 @@ func SubsonicGetQueue() (*PlayQueue, error) {
return &data.Response.PlayQueue, nil
}

func SubsonicAddToPlaylist(songID string, playlistID string) {
params := map[string]string{
"playlistId": playlistID,
"songIdToAdd": songID,
func SubsonicAddToPlaylist(playlistID string, songIds []string) {
params := url.Values{
"playlistId": {playlistID},
}

for _, id := range songIds {
params.Add("id", id)
}

_, _ = subsonicGET("/updatePlaylist", params)
}

func SubsonicCreateShare(ID string) (string, error) {
params := map[string]string{
"id": ID,
func SubsonicCreateShare(ids []string) (string, error) {
params := url.Values{}

for _, id := range ids {
params.Add("id", id)
}

data, err := subsonicGET("/createShare", params)
if err != nil {
log.Printf("[ERROR] API Error in CreateShare: %v", err)
return "", err
log.Printf("[ERROR] API Error in CreateShare: %s", err)
}

url := data.Response.Shares.ShareList[0].URL
log.Printf("[SHARE] Generated Share URL: %s", url)
return data.Response.Shares.ShareList[0].URL, nil

return url, nil
}

func SubsonicGetLyrics(ID string) ([]StructuredLyrics, error) {
params := map[string]string{
"id": ID,
params := url.Values{
"id": {ID},
}

data, err := subsonicGET("/getLyricsBySongId", params)
Expand Down
17 changes: 9 additions & 8 deletions internal/api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,15 @@ type GlobalKeybinds struct {
}

type NavigationKeybinds struct {
Up []string `toml:"up"`
Down []string `toml:"down"`
Top []string `toml:"top"`
Bottom []string `toml:"bottom"`
Select []string `toml:"select"`
PlayShuffled []string `toml:"play_shuffled"`
GoHalfPageUp []string `toml:"go_half_page_up"`
GoHalfPageDown []string `toml:"go_half_page_down"`
Up []string `toml:"up"`
Down []string `toml:"down"`
Top []string `toml:"top"`
Bottom []string `toml:"bottom"`
Select []string `toml:"select"`
ToggleSelection []string `toml:"toggle_selection"`
PlayShuffled []string `toml:"play_shuffled"`
GoHalfPageUp []string `toml:"go_half_page_up"`
GoHalfPageDown []string `toml:"go_half_page_down"`
}

type SearchKeybinds struct {
Expand Down
15 changes: 8 additions & 7 deletions internal/api/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ max_rating = 0 # Exclude songs with a rating less than or equal to this number (
hard_quit = ['ctrl+c']

[keybinds.navigation]
up = ['k', 'up']
down = ['j', 'down']
top = ['gg']
bottom = ['G']
select = ['enter']
play_shuffled = ['alt+enter']
go_half_page_up = ['ctrl+u']
up = ['k', 'up']
down = ['j', 'down']
top = ['gg']
bottom = ['G']
select = ['enter']
toggle_selection = ['x']
play_shuffled = ['alt+enter']
go_half_page_up = ['ctrl+u']
go_half_page_down = ['ctrl+d']

[keybinds.search]
Expand Down
Loading
Loading